bamaer commented on PR #8306:
URL: https://github.com/apache/hop/pull/8306#issuecomment-5630549745

   ## Verdict
   
   The approach is right. The RFC 3986 reasoning in the description is correct: 
a query-only `ServiceHandler` genuinely cannot work, and a directory-shaped 
path is the only thing that gives the iframe a document base. The layering is 
good too — pure path logic in `ExplorerFileServing` with no RAP/SWT types so 
`hop-ui` can test it, RAP-specific bits behind an interface, I/O inside 
`uiSession.exec` so HopVfs session namespaces resolve correctly, and 
origin-relative URLs so a TLS proxy doesn't mixed-content-block the iframe.
   
   The extension allow-list defaults to deny rather than blocking a denylist, 
the token is bound to *both* the RAP UI session and the HTTP session rather 
than either alone, the desktop path degrades to `setText()` instead of throwing 
when a VFS scheme isn't browser-fetchable, and both `web.xml` copies are kept 
in sync as the file comment asks. The sandbox tests cover the cases that matter 
(`%2e%2e`, `C:/`, nested `../../`, folder, unknown extension).
   
   Four things I'd want addressed before merge.
   
   ### 1. No CSP — script in an explorer file runs in the Hop Web origin
   
   `/explorer-file/...` is same-origin with `/ui`. Any `<script>` in an HTML 
file the user opens, a directly-navigated `.svg`, or a `.js` under the explorer 
root executes with the user's session cookie and can call `/hop/api/v1/*` and 
`/hop/*` as that user.
   
   `Browser.setText()` also rendered same-origin, so this isn't wholly new — 
but the PR adds `js` and `svg` to the allow-list and makes the content directly 
fetchable by URL, which is the moment to close it. The PR's Security section 
lists nosniff, no-store, token, sandbox and size cap; CSP is the one missing 
lever.
   
   There's a real trade-off, so I'd rather name it than prescribe a header:
   
   - **Strict** (`default-src 'none'; img-src 'self' data:; style-src 'self' 
'unsafe-inline'; font-src 'self'`) kills script entirely and keeps everything 
the PR is for. It also breaks `updateTitleFromPageTitle()` on Hop Web — that 
calls `wBrowser.evaluate("return document.title;")`, which needs to inject 
script into the iframe document.
   - **Pragmatic** (`connect-src 'none'; form-action 'none'; base-uri 'none'`) 
leaves in-page script working so the tab title survives, but blocks the 
fetch-the-Hop-API escalation, which is the part that actually matters.
   
   I'd take the pragmatic one unless losing the page-title feature on web is 
acceptable. Separately: is `js` needed in the allow-list at all, or is it there 
speculatively?
   
   ### 2. The lease keeps a stale HTTP session id
   
   `ExplorerFileLease` makes `httpSessionId` final, and on the existing-lease 
path `ExplorerFileRegistry.getOrCreate` only calls `lease.setRootVfsUri(...)` — 
it never refreshes the session id. Containers rotate the HTTP session id on 
authentication (session-fixation defence). After that rotation `sessionMatches` 
fails permanently, and every explorer file 404s for the rest of the UI session 
with nothing in the UI explaining why.
   
   Cheapest fix: drop the stored id and derive it at check time from 
`lease.getUiSession().getHttpSession().getId()`.
   
   ### 3. The path is URL-decoded two extra times
   
   `HttpServletRequest.getPathInfo()` is decoded by the container per the 
servlet spec. `sanitizeRelativePath` then decodes it again, and 
`resolveUnderRoot` sanitizes a *third* time on an already-sanitized string from 
`parsePathInfo`.
   
   Not a traversal hole — the `..`, `:` and leading-`/` checks all run after 
the decode, and the `%252e%252e` / `%252f` cases walk through to rejection. But 
it breaks filenames containing `%`. Verified round trip through 
`buildPublicPath` -> container decode -> `sanitizeRelativePath`:
   
   ```
   file=100% done.html   url=100%25%20done.html   -> throws 
IllegalArgumentException -> swallowed -> 404
   file=a%20b.html       url=a%2520b.html         -> resolves to "a b.html"  
(wrong file -> 404)
   file=My File.html     url=My%20File.html       -> OK
   ```
   
   Sanitize once, at the boundary, and treat the input as already decoded.
   
   ### 4. `sanitizeRelativePath` rejects any path containing `:`
   
   `decoded.contains(":")` is meant to catch schemes, but it also rejects legal 
filenames on Linux and macOS — `report:2026-09-11.html`. Those files get 
`urlFor() == null` and silently fall back to `setText()`, so the exact bug this 
PR fixes still bites them, with no diagnostic. Anchor the check to a scheme 
prefix on the first segment instead of a substring test.
   
   ---
   
   Reviewed from the diff; I did not check out the branch or run the build, so 
the "89 tests pass" claim is unverified on my end.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to