-
Notifications
You must be signed in to change notification settings - Fork 493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds load json ssrf mitigation #2467
Adds load json ssrf mitigation #2467
Conversation
build.gradle
Outdated
@@ -109,7 +109,7 @@ subprojects { | |||
|
|||
ext { | |||
// NB: due to version.json generation by parsing this file, the next line must not have any if/then/else logic | |||
neo4jVersion = "4.4.1" | |||
neo4jVersion = "4.4.4-SNAPSHOT" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A new 4.4 version of the database needs to be released and substituted here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ncordon If we don't use a non snapshot version we aren't able to test the PR in GH can you please change it to 4.4.3?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code we need is in 4.4.4, and to release 4.4.4 we are going to need this to be merged on red. The CI of the database will compile the APOC code overriding the version.
So even bumping this, don't expect the CI to pass.
After the database has been released, we can bump here to 4.4.4 and release a new version of APOC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was done without the need to depend on 4.4.4 in the end
} | ||
|
||
public static Stream<Object> loadJson(Object urlOrBinary, Map<String,Object> headers, String payload, String path, boolean failOnError, String compressionAlgo, List<String> options) { | ||
public static Stream<Object> loadJson(Object urlOrBinary, Map<String,Object> headers, String payload, String path, boolean failOnError, String compressionAlgo, List<String> options, ApocConfig apocConfig) { | ||
try { | ||
if (urlOrBinary instanceof String) { | ||
String url = (String) urlOrBinary; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this check be done in checkReadAllowed
, where the other access rules as processed? With the check here, you can still make calls that violate the blocklist using apoc.load.xml
, apoc.xml.import
, apoc.load.xmlSimple
, apoc.load.xls
, apoc.cypher.runFiles
and so on.
Similarly, we should process the blocklist in checkWriteAllowed
, otherwise people can violate the blocklist by sending POST requests and other output network connections?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes we should not pass the full apoc config through, either just what we need or better like Jake said handle it in the single place where we control the loading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also you don't need to pass apocConfig
through but use ApocConfig.getConfig().methodCall()
there are already some methods for checking, we can handle the address as part of that.
so you would rather do something like ApocConfig#isIpAllowed(ip)
or ApocConfig#isHostNameAllowed(hostname)
need to make sure though to resolve the final hostname properly to ip-address (after all the http-redirects are handled).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ncordon please look at the comments above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jexp I have addressed the concern for redirects in a pending PR: https://github.com/neo-technology/neo4j/pull/14171. The logic for the blocking lives in the kernel of the database and here I am reusing the same logic. So once that's merged we should be safe with respect to redirects (I hope).
@conker84 I get the need for checkReadAllowed
, but checkWriteAllowed
works only with filenames, which this blocklist doesn't include, judging by its signature?
Do we have any situation where we can do a POST to a path in a remote server?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been addressed.
With respect to checkWriteAllowed
, we've deemed that change is not necessary as it only affects files. POST requests (load json ones for example) go through the checkReadAllowed
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
write list also works with urls e.g. for s3 URLs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…om a blocked ip range
bcc6103
to
a00abfc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be not necessary
edit. github seems that cutted my review, lemme do that again
} | ||
|
||
public static Stream<Object> loadJson(Object urlOrBinary, Map<String,Object> headers, String payload, String path, boolean failOnError, String compressionAlgo, List<String> options) { | ||
public static Stream<Object> loadJson(Object urlOrBinary, Map<String,Object> headers, String payload, String path, boolean failOnError, String compressionAlgo, List<String> options, ApocConfig apocConfig) { | ||
try { | ||
if (urlOrBinary instanceof String) { | ||
String url = (String) urlOrBinary; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ncordon please look at the comments above
61ae529
to
9ca37c7
Compare
9ca37c7
to
2670ade
Compare
c9cdfb9
to
fba2b90
Compare
fba2b90
to
13814da
Compare
5ac2f68
to
2c06679
Compare
@@ -60,6 +60,7 @@ dependencies { | |||
exclude module: "snakeyaml" | |||
} | |||
compile group: 'org.yaml', name: 'snakeyaml', version: '1.26' | |||
compile group: 'com.github.seancfoley', name: 'ipaddress', version: '5.3.3' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed now if we want to avoid transitive dependencies that come from the database in 4.4.4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but then we need to take it out when 4.4.4 is out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jexp My idea is to keep in 4.4.x so we can cover also older Neo4j versions, and remove it from 5.0
432ff3d
to
c5a8ca8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much @ncordon
What
Uses Neo4j internal option
unsupported.dbms.cypher_ip_blocklist
, which consists on a list of ip addresses in CDIR notation, i.e. ip + mask for subnets, e.g.192.167.2.3/8, 192.234.3.123/16
. When using theapoc.load.json(url)
command, the url will be looked up in a DNS resolver and we will fail if it is on the list of blocked ip addresses.Why
Users can try to load data from any url (including internal ones), which could expose files the user does not have permissions to see from outside.