Conversation
… header validation - Implemented CORS origin whitelisting to replace wildcard `*` policy in the HTTP server. - Added a security filter to validate custom headers and origins. - Introduced configurable allowed origins to support browser extensions and JabMap.
…ensions - Introduced a PIN generation feature in preferences for pairing browser extensions with the HTTP server. - Implemented bearer token authentication for secure communication between paired extensions and the server. - Updated the security filter to validate tokens and manage pairing endpoints.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| Injector.setModelOrService(ConnectorTokenManager.class, JabRefGUI.connectorTokenManager); | ||
|
|
||
| JabRefGUI.httpServerManager = new HttpServerManager(); | ||
| JabRefGUI.httpServerManager.setTokenManager(JabRefGUI.connectorTokenManager); |
There was a problem hiding this comment.
Why putting this a second time in a static context, if you already put this into the injector already?
There was a problem hiding this comment.
Good catch, removed the static context
| Injector.setModelOrService(RemoteListenerServerManager.class, JabRefGUI.remoteListenerServerManager); | ||
|
|
||
| JabRefGUI.connectorTokenManager = new ConnectorTokenManager(preferences.getRemotePreferences()); | ||
| Injector.setModelOrService(ConnectorTokenManager.class, JabRefGUI.connectorTokenManager); |
There was a problem hiding this comment.
Isn't putting the token manager in a static context also a security risk on its own?
| private String activePin = ""; | ||
| private Instant pinExpiration = Instant.MIN; | ||
|
|
||
| public ConnectorTokenManager(RemotePreferences remotePreferences) { |
There was a problem hiding this comment.
I have the very strong suspicion, that this class is not a manager at all.
This is just a couple of helper methods if I see it correctly around a variable active pin and remoteprefences. Looks like to me that this could also just be a utility class.
There was a problem hiding this comment.
For me, it was more of a manager class, since it's stateful (active PIN, expiration time). I would expect a utility class to be completely stateless.
There was a problem hiding this comment.
State can be stored in preferences or state manager. But we are trying to avoid excessive growth of singletons/managers
There was a problem hiding this comment.
The token should be stored in the preferences to survive JabRef sessions.
PIN is only used temporarily during authentication process to generate the token.
PIN -- "Manager", maybe better "AuthenticationTask"?
Token -- Preferences
Need to check the code if this is fulfilled.
There was a problem hiding this comment.
Token is already saved in Preferences. I renamed the class to ConnectorAuthenticationTask
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
I was curious about the cite as you write (cayw) endpoint and if its still working with the security filter, it still works. |
* Chore(deps): Bump pdfbox from 3.0.6 to 3.0.7 in /versions Bumps `pdfbox` from 3.0.6 to 3.0.7. Updates `org.apache.pdfbox:fontbox` from 3.0.6 to 3.0.7 Updates `org.apache.pdfbox:pdfbox` from 3.0.6 to 3.0.7 Updates `org.apache.pdfbox:xmpbox` from 3.0.6 to 3.0.7 --- updated-dependencies: - dependency-name: org.apache.pdfbox:fontbox dependency-version: 3.0.7 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.pdfbox:pdfbox dependency-version: 3.0.7 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.pdfbox:xmpbox dependency-version: 3.0.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * fix new schema urls --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Siedlerchr <siedlerkiller@gmail.com>
This comment has been minimized.
This comment has been minimized.
This should be an issue easy to solve? |
Thanks a lot, this is really helpful. It's scary how easy websites can communicate with stuff on localhost (Firefox doesn't even show the confirmation prompt that you mentioned). Your example page also explains why my tests were failing: I always sent some custom headers with it, so the preflight was issued and then the main request got blocked. That brings me to
If I try your example in Firefox & Edge, the "with headers" option is not able to get anything from localhost as the preflight is coming back without tha ACAPN header. Is this working for you/on Chrome? So requiring the Having such a header is anyway a good idea as you don't want to accept requests that are purely accidentally sent to the 'wrong' localhost port.
As extensions have the power to change the headers (also protected ones like 'origin' [not totally sure about requests to localhost, but the origin of requests to other websites can definitely be changed]), there is not much you can do here anyway. Also if the user decides to install an extension that then talks to JabRef, what's the problem? We are not a bank that needs to force users to go through hurdles to protect their money. If you really want to have a higher security standard, then I would suggest to do the token exchange automatically via native messing (which has a built-in verification of the extensions that are allowed to trigger the run of an application). |
We should investigate.
The trade-off discussion is between
@FynnianB Am I missing some trade-offs here? |
…rity * upstream/main: (204 commits) New Crowdin updates (JabRef#15669) Fix OpenRewrite (JabRef#15670) Udpate heylogs (and fix CHANGELOG.md) (JabRef#15671) Improve security and prevent shell injection for push2applications (JabRef#15628) Fix depdency analysis (JabRef#15668) Always use CI-local "gradle", instead of gradlew (JabRef#15667) Change OpenRewrite task to use rewriteDryRun (JabRef#15664) Add small documentation to parameter (JabRef#15666) Fix markbaseChanged for "imported entries" (JabRef#15610) Add forgotten --fresh chore(deps): update dependency com.github.ben-manes.caffeine:caffeine to v3.2.4 (JabRef#15662) chore(deps): update jackson monorepo to v3.1.3 (JabRef#15659) chore(deps): update dependency org.glassfish.hk2:hk2-utils to v4.0.1 (JabRef#15657) chore(deps): update dependency org.glassfish.hk2:hk2-locator to v4.0.1 (JabRef#15656) fix gemsfx missing icon resolving (JabRef#15655) chore(deps): update dependency org.glassfish.hk2:hk2-api to v4.0.1 (JabRef#15654) chore(deps): update dependency org.postgresql:postgresql to v42.7.11 (JabRef#15634) Chore(deps): Bump tools.jackson:jackson-bom in /versions (JabRef#15653) Chore(deps): Bump dev.langchain4j:langchain4j-bom in /versions (JabRef#15652) Chore(deps): Bump com.dlsc.gemsfx:gemsfx in /versions (JabRef#15651) ...
|
The requested changes were not addressed for 10 days. Please follow-up in the next 10 days or your PR will be automatically closed. You can check the contributing guidelines for hints on the pull request process. |
|
As usual, after submitting a thesis, students re-focus themselves. This PR is important - we need to leave it open (and finish before 6.0 release) |
|
put it as freeze as we don't have time any more to think. We will continue as soon as we find time. |
|
Also Safari needs to be investigated: JabRef/JabRef-Browser-Extension#681 (comment) |
Related issues and pull requests
Closes no related issue
PR Description
This PR hardens the HTTP server used for browser extension communication by adding two security layers:
First, CORS origin whitelisting and a custom
X-JabRef-Connectorheader validation ensure only legitimate browser extension requests are processed.Second, a PIN-based pairing mechanism generates a bearer token that authenticates all subsequent API requests, preventing unauthorized extensions from accessing the endpoint.
This PR is part of my bachelorthesis regarding the communication between the browser extension and the JabRef Desktop-App. The corresponding PR in the JabRef-Browser-Extension-fresh repository will follow shortly.
Important: This breaks the current communication with the fresh extension because it enforces the
X-JabRef-Connectorheader so this PR should not be merged before the corresponding PR in JabRef-Browser-Extension-fresh is merged._Hint: This PR will follow another one which adds the MADR for it.
Steps to test
Quick test with curl (no extension needed):
Start JabRef, enable the HTTP server in preferences
Verify the health check still works without headers:
Expected: HTML response (200 OK)
Request a protected endpoint without
Origin(local tool behavior, allowed):Expected: 200 OK
Request with an unknown origin (simulates a malicious website):
Expected: 403 Forbidden
Request with extension origin but no custom header:
Expected: 403 Forbidden
Request with extension origin and custom header but no token:
Expected: 401 Unauthorized
Generate a PIN in Preferences > General, then pair:
Expected:
{"token":"..."}(200 OK)Use the token:
Expected: 200 OK
How the browser extension will use this later:
The extension will send
X-JabRef-ConnectorandAuthorization: Bearer <token>on every request. On first use, a pairing dialog will prompt the user for the PIN shown in JabRef. The token is stored inchrome.storage.localand reused across sessions.Checklist
CHANGELOG.mdin a way that can be understood by the average user (if change is visible to the user)