Disabling OWASP CSRF protection in Docker: openmrs/openmrs-reference-application-distro:qa

while running the openmrs/openmrs-reference-application-distro:qa locally, (http://localhost:8080/openmrs) making a POST to it with Integrated Tests, I get an error UnclassifiedServerFailure HTTP 302 caused by lack of a CSRF-Token.

Question:

  1. How can i disable csrf-token protection with the running docker container

  2. As an alternative, how can i append an automatically generated token to the request header that matches the one on the running instance.

cc @dkayiwa @ibacher @burke

You can disable CSRF protection from the csrfguard.properties file in the OpenMRS application data folder by changing the value of the org.owasp.csrfguard.Enabled property from true to false.

Though you do not have to disable it to make REST calls. Did you start by logging in successfully via REST?

below is my request

POST /openmrs/ws/rest/v1/session HTTP/1.1
Host: localhost:8080
Authorization: Basic YWRtaW46QWRtaW4xMjM=
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: d737291c-fd51-7a4f-cf62-692667c13015

{
	"sessionLocation": "b1a8b05e-3542-4037-bbd3-998ee9c40574",
	"locale": "en"
}

However, this is still failing and prompting me to add a csrf-token. Am wondering why this is really working fine when i change the url to point to the dev3.openmrs.org and location to point to the Community Outreach

I am sure that if i make it work via Postman, it will be simpler making it work with plain java

this is really hard while using docker. I think it requires accessing the files of the running containers and rebuilding, stoping the container, and rebuilding it again.

dev3.openmrs.org is not running platform 2.6.0-SNAPSHOT. Which is the only platform version that has CSRF protection.

this really answers why csrf-token isn’t needed there

This doesn’t seem to be the case:

POST /openmrs/ws/rest/v1/session HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Basic YWRtaW46QWRtaW4xMjM=
Connection: keep-alive
Content-Length: 16
Content-Type: application/json
Host: qa-refapp.openmrs.org
User-Agent: HTTPie/3.2.1

{
    "locale": "en"
}


HTTP/1.1 302 Found
Connection: keep-alive
Content-Length: 0
Date: Tue, 31 May 2022 13:30:06 GMT
Location: http://qa-refapp.openmrs.org/openmrs/error.html
Server: nginx/1.10.3 (Ubuntu)
Set-Cookie: JSESSIONID=BAD20D99333A824ED3C8960B749DAC83; Path=/openmrs; HttpOnly
Strict-Transport-Security: max-age=15768000

(The redirect is to the “missing CSRF token page”).

Maybe we need to add a rule like:

org.owasp.csrfguard.unprotected.apis=%servletContext%/ws/*

By default?

Are our REST APIs free from CSRF attacks? Or should we just provide an API for them to get the CSRF token to pass in subsequent calls for HTTP operations that modify server side state? Something like below:

  1. Make a GET request to login.
  2. Get a CSRF-TOKEN from the second GET , using JSESSIONID from previous request.
  3. Use the CSRF-TOKEN for POST and DELETE
1 Like

No, they aren’t. Arguably, though, a CSRF request to the backend is somewhat indistinguishable from a “standard” API call.

That seems workable. Is there a way we could check whether the CSRF token is required? I suppose we can always check the backend version and just assume 2.6.0+ requires a CSRF token? (I’m thinking in terms of backwards compatibility for versions that need a CSRF and those that don’t)

Should we use an HTTP header, during authentication, for the client to know whether the CSRF token is required?

I think that should work.