Don't send token in request body.

Instead, we want to hash a header to sign a request with a client nonce,
http method and URL. This is a first step towards protecting the backend
against eavesdropping.

Please note that this will still be susceptible to replay attacks.
This commit is contained in:
Andre Medeiros 2018-10-16 12:48:51 -04:00 committed by Pascal Precht
parent 70b62bdc16
commit 428f591330
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
4 changed files with 114 additions and 40 deletions

View File

@ -496,7 +496,7 @@
},
"axios": {
"version": "0.18.0",
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": {
"follow-redirects": "^1.3.0",
@ -777,7 +777,7 @@
},
"babel-plugin-istanbul": {
"version": "4.1.6",
"resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
"integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
"requires": {
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
@ -823,7 +823,7 @@
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U="
},
"babel-plugin-syntax-trailing-function-commas": {
@ -1573,7 +1573,7 @@
},
"browserify-aes": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"requires": {
"buffer-xor": "^1.0.3",
@ -1607,13 +1607,21 @@
},
"browserify-rsa": {
"version": "4.0.1",
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"requires": {
"bn.js": "^4.1.0",
"randombytes": "^2.0.1"
}
},
"browserify-sha3": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.1.tgz",
"integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=",
"requires": {
"js-sha3": "^0.3.1"
}
},
"browserify-sign": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
@ -1655,7 +1663,7 @@
},
"buffer": {
"version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"requires": {
"base64-js": "^1.0.2",
@ -2321,7 +2329,7 @@
},
"create-hash": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"requires": {
"cipher-base": "^1.0.1",
@ -2333,7 +2341,7 @@
},
"create-hmac": {
"version": "1.1.7",
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"requires": {
"cipher-base": "^1.0.3",
@ -2807,7 +2815,7 @@
},
"diffie-hellman": {
"version": "5.0.3",
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"requires": {
"bn.js": "^4.1.0",
@ -2936,7 +2944,7 @@
},
"duplexer": {
"version": "0.1.1",
"resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
},
"duplexer3": {
@ -3364,7 +3372,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"requires": {
"graceful-fs": "^4.1.2",
@ -3527,7 +3535,7 @@
},
"events": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
},
"eventsource": {
@ -3662,7 +3670,7 @@
},
"express": {
"version": "4.16.3",
"resolved": "http://registry.npmjs.org/express/-/express-4.16.3.tgz",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
"integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
"requires": {
"accepts": "~1.3.5",
@ -3956,7 +3964,7 @@
},
"finalhandler": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"requires": {
"debug": "2.6.9",
@ -4575,7 +4583,7 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"get-value": {
@ -5036,7 +5044,7 @@
},
"http-errors": {
"version": "1.6.3",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"requires": {
"depd": "~1.1.2",
@ -5289,7 +5297,7 @@
},
"inline-style-prefixer": {
"version": "2.0.5",
"resolved": "http://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz",
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz",
"integrity": "sha1-wVPH6I/YT+9cYC6VqBaLJ3BnH+c=",
"requires": {
"bowser": "^1.0.0",
@ -5421,7 +5429,7 @@
},
"is-builtin-module": {
"version": "1.0.0",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"requires": {
"builtin-modules": "^1.0.0"
@ -5563,7 +5571,7 @@
},
"is-obj": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"is-path-cwd": {
@ -6389,6 +6397,11 @@
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.8.tgz",
"integrity": "sha512-hm2nYpDrwoO/OzBhdcqs/XGT6XjSuSSCVEpia+Kl2J6x4CYt5hISlVL/AYU1khoDXv0AQVgxtdJySb9gjAn56Q=="
},
"js-sha3": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz",
"integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@ -6482,7 +6495,7 @@
},
"json5": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
},
"jsonfile": {
@ -6514,6 +6527,15 @@
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
"integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE="
},
"keccakjs": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.1.tgz",
"integrity": "sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0=",
"requires": {
"browserify-sha3": "^0.0.1",
"sha3": "^1.1.0"
}
},
"killable": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz",
@ -6569,7 +6591,7 @@
},
"load-json-file": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"requires": {
"graceful-fs": "^4.1.2",
@ -7000,7 +7022,7 @@
},
"minimist": {
"version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mixin-deep": {
@ -7024,7 +7046,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
@ -7067,8 +7089,7 @@
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
"optional": true
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA=="
},
"nanomatch": {
"version": "1.2.13",
@ -7497,7 +7518,7 @@
},
"parse-asn1": {
"version": "5.1.1",
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
"requires": {
"asn1.js": "^4.0.0",
@ -7676,7 +7697,7 @@
"dependencies": {
"async": {
"version": "1.5.2",
"resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
}
}
@ -9286,7 +9307,7 @@
},
"react-redux": {
"version": "5.0.7",
"resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
"integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==",
"requires": {
"hoist-non-react-statics": "^2.5.0",
@ -9885,7 +9906,7 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
@ -10038,13 +10059,21 @@
},
"sha.js": {
"version": "2.4.11",
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"sha3": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.2.tgz",
"integrity": "sha1-pmxQmN5MJbyIM27ItIF9AFvKe6k=",
"requires": {
"nan": "2.10.0"
}
},
"shallowequal": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz",
@ -10460,7 +10489,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
@ -10571,7 +10600,7 @@
},
"table": {
"version": "4.0.3",
"resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz",
"integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
"requires": {
"ajv": "^6.0.1",
@ -10662,7 +10691,7 @@
},
"through": {
"version": "2.3.8",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"thunky": {
@ -11724,7 +11753,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"string-width": "^1.0.1",

View File

@ -37,6 +37,7 @@
"history": "^4.7.2",
"html-webpack-plugin": "2.29.0",
"jest": "20.0.4",
"keccakjs": "0.2.1",
"monaco-editor": "^0.14.3",
"monaco-editor-webpack-plugin": "^1.5.4",
"object-assign": "4.1.1",

View File

@ -1,9 +1,36 @@
import axios from "axios";
import keccak from "keccakjs";
function hash(cnonce, token, type, path, params = {}) {
let hash = new keccak();
hash.update(JSON.stringify(cnonce));
hash.update(token);
hash.update(type.toUpperCase());
hash.update(`/embark-api${path}`);
return hash.digest('hex');
}
function request(type, path, params = {}) {
axios.defaults.headers.common['Authorization'] = params.credentials.token;
const endpoint = `http://${params.credentials.host}/embark-api${path}`;
return axios[type](endpoint, params)
const cnonce = Date.now() + Math.random();
// Extract credentials out of the params and delete so the token doesn't get sent
// as cleartext.
let credentials = params.credentials;
delete params.credentials;
let requestHash = hash(cnonce, credentials.token, type, path, params);
const endpoint = `http://${credentials.host}/embark-api${path}`;
const req = {
method: type,
url: endpoint,
headers: {
'X-Embark-Request-Hash': requestHash,
'X-Embark-Cnonce': cnonce
}
}
return axios(req, params)
.then((response) => {
return (response.data && response.data.error) ? {error: response.data.error} : {response, error: null};
}).catch((error) => {

View File

@ -1,5 +1,6 @@
const uuid = require('uuid/v1');
const utils = require("../../utils/utils.js")
const keccak = require('keccakjs');
const ERROR_OBJ = {error: __('Wrong authentication token. Get your token from the Embark console by typing `token`')};
@ -14,12 +15,25 @@ class Authenticator {
this.registerEvents();
}
generateRequestHash(req) {
let cnonce = req.headers['x-embark-cnonce'];
let hash = new keccak();
hash.update(cnonce);
hash.update(this.authToken);
hash.update(req.method);
hash.update(req.url);
return hash.digest('hex');
}
registerCalls() {
let self = this;
this.embark.registerAPICall(
'post',
'/embark-api/authenticate',
(req, res) => {
if (req.body.token !== this.authToken) {
let hash = self.generateRequestHash(req);
if(hash !== req.headers['x-embark-request-hash']) {
this.logger.warn(__('Someone tried and failed to authenticate to the backend'));
this.logger.warn(__('- User-Agent: %s', req.headers['user-agent']));
this.logger.warn(__('- Referer: %s', req.headers.referer));
@ -51,14 +65,17 @@ class Authenticator {
}
registerEvents() {
let self = this;
this.events.once('outputDone', () => {
const {port, host} = this.embark.config.webServerConfig;
this.logger.info(__('Access the web backend with the following url: %s',
(`http://${host}:${port}/embark?token=${this.authToken}`.underline)));
});
this.events.setCommandHandler('authenticator:authorize', (token, cb) => {
if (token !== this.authToken) {
this.events.setCommandHandler('authenticator:authorize', (req, cb) => {
let hash = self.generateRequestHash(req);
if(hash !== req.headers['x-embark-request-hash']) {
return cb(ERROR_OBJ);
}
cb();