I wrote a small javascript to test digest authentication on monerod
and monero-wallet-rpc
.
When running on a http
(no tls) website, authentication works, and I get my response.
Then trying the same javascript on a https
website, I get the folowing log output from the wallet server.
D handle_accept
D New server for RPC connections, SSL autodetection
D set m_connection_type = RPC
D Spawned connection #4 to 0.0.0.0 currently we have sockets count:2
D test, connection constructor set m_connection_type=1
T [sock 0x7f9bdc044680] new connection from client.ip.address:62186 INC to server.ip.address:38083, total sockets objects 2
T New connection from host client.ip.address: 0
T Setting 00:00:10 expiry
D connection type RPC server.ip.address:38083 <--> client.ip.address:62186 (via client.ip.address:62186)
T Setting 00:00:10.102921 expiry
D SSL detection buffer, 517 bytes: 22 3 1 2 0 1 0 1 252
D That looks like SSL
D handle_accept
D New server for RPC connections, SSL autodetection
D set m_connection_type = RPC
D Spawned connection #5 to 0.0.0.0 currently we have sockets count:3
D test, connection constructor set m_connection_type=1
T [sock 0x7f9bdc02dce0] new connection from client.ip.address:61715 INC to server.ip.address:38083, total sockets objects 3
T New connection from host client.ip.address: 1
T Setting 00:00:10 expiry
D connection type RPC server.ip.address:38083 <--> client.ip.address:61715 (via client.ip.address:61715)
T Setting 00:00:10.072703 expiry
D SSL detection buffer, 517 bytes: 22 3 1 2 0 1 0 1 252
D That looks like SSL
E SSL handshake failed, connection dropped: short read
E SSL handshake failed
T Closed connection from host client.ip.address: 2
D SSL handshake success
T [sock 9] Socket destroyed
D Destructing connection #4 to client.ip.address
T [sock 8] Some not success at read: sslv3 alert bad certificate:336151570
T [sock 8] Some problems at read: sslv3 alert bad certificate:336151570
T Closed connection from host client.ip.address: 1
T [sock 8] Socket destroyed
D Destructing connection #3 to client.ip.address
And I get a generic error in Firefox.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://server.ip.address:38083/json_rpc. (Reason: CORS request did not succeed).
What am I missing? Do I need to tell monero about my certificate?
EDIT: Added a successful session. No HTTPS and No certificates.
Website and the monero stuff is on the same host/ip-address.
T Throttle <<< global-IN: packet of ~496b (from 496 b) Speed AVG= 0[w=9.757] 0[w=9.757] / Limit=16 KiB/sec [496 0 0 0 0 0 0 0 0 0 ]
T HTTP HEAD:
T Host: host.example.com:38083
T User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
T Accept: */*
T Accept-Language: en,da;q=0.5
T Accept-Encoding: gzip, deflate
T Access-Control-Request-Method: POST
T Access-Control-Request-Headers: content-type
T Referer: http://host.example.com/test-05/
T Origin: http://host.example.com
T DNT: 1
T Connection: keep-alive
T Pragma: no-cache
T Cache-Control: no-cache
T
T HTTP_RESPONSE_HEAD: <<
T HTTP/1.1 200 OK
T Server: Epee-based
T Content-Length: 0
T Last-Modified: Thu, 19 Mar 2020 14:55:13 GMT
T Accept-Ranges: bytes
T Access-Control-Allow-Origin: http://host.example.com
T Access-Control-Expose-Headers: www-authenticate
T Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
T Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS
T
T Moving counter buffer by 1 second 0 < 300414 (last time 0)
T Throttle throttle_speed_out: packet of ~373b (from 373 b) Speed AVG= 0[w=1] 0[w=1] / Limit=16 KiB/sec [373 0 0 0 0 0 0 0 0 0 ]
D do_send_chunk() NOW SENSD: packet=373 B
T Setting 00:05:00 expiry
T Setting 00:05:00 expiry
T [client.ip.addr:60290 INC] [sock 8] Async send calledback 373
D handle_accept
D New server for RPC connections, SSL autodetection
D set m_connection_type = RPC
D Spawned connection #8 to 0.0.0.0 currently we have sockets count:3
D test, connection constructor set m_connection_type=1
T [sock 0x7f147801ec40] new connection from client.ip.addr:34239 INC to server.ip.addr:38083, total sockets objects 3
T New connection from host client.ip.addr: 1
T Setting 00:00:10 expiry
D connection type RPC server.ip.addr:38083 <--> client.ip.addr:34239 (via client.ip.addr:34239)
T Setting 00:00:09.738196 expiry
D SSL detection buffer, 538 bytes: 80 79 83 84 32 47 106 115 111
D That does not look like SSL
T Moving counter buffer by 1 second 0 < 300415 (last time 0)
T Throttle throttle_speed_in: packet of ~538b (from 538 b) Speed AVG= 0[w=1] 0[w=1] / Limit=16 KiB/sec [538 0 0 0 0 0 0 0 0 0 ]
T Moving counter buffer by 1 second 300413 < 300415 (last time 300414)
T Moving counter buffer by 1 second 300414 < 300415 (last time 300415)
T Throttle <<< global-IN: packet of ~538b (from 538 b) Speed AVG= 0[w=9.159] 0[w=9.159] / Limit=16 KiB/sec [538 0 496 0 0 0 0 0 0 0 ]
T HTTP HEAD:
T Host: host.example.com:38083
T User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
T Accept: */*
T Accept-Language: en,da;q=0.5
T Accept-Encoding: gzip, deflate
T Content-Type: application/json; charset=utf-8
T Content-Length: 61
T Origin: http://host.example.com
T DNT: 1
T Connection: keep-alive
T Referer: http://host.example.com/test-05/
T Pragma: no-cache
T Cache-Control: no-cache
T
T HTTP_RESPONSE_HEAD: <<
T HTTP/1.1 401 Unauthorized
T Server: Epee-based
T Content-Length: 98
T Content-Type: text/html
T Last-Modified: Thu, 19 Mar 2020 14:55:14 GMT
T Accept-Ranges: bytes
T Access-Control-Allow-Origin: http://host.example.com
T Access-Control-Expose-Headers: www-authenticate
T Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS
T WWW-authenticate: Digest qop="auth",algorithm=MD5,realm="monero-rpc",nonce="TxiQqEIvHWWbjks8rvdMRA==",stale=false
T WWW-authenticate: Digest qop="auth",algorithm=MD5-sess,realm="monero-rpc",nonce="TxiQqEIvHWWbjks8rvdMRA==",stale=false
T
T Moving counter buffer by 1 second 0 < 300415 (last time 0)
T Throttle throttle_speed_out: packet of ~665b (from 665 b) Speed AVG= 0[w=1] 0[w=1] / Limit=16 KiB/sec [665 0 0 0 0 0 0 0 0 0 ]
D do_send_chunk() NOW SENSD: packet=665 B
T Setting 00:05:00 expiry
T Setting 00:05:00 expiry
T [client.ip.addr:34239 INC] [sock 9] Async send calledback 665
T Throttle throttle_speed_in: packet of ~758b (from 758 b) Speed AVG= 0[w=1] 0[w=1] / Limit=16 KiB/sec [1296 0 0 0 0 0 0 0 0 0 ]
T Throttle <<< global-IN: packet of ~758b (from 758 b) Speed AVG= 0[w=9.425] 0[w=9.425] / Limit=16 KiB/sec [1296 0 496 0 0 0 0 0 0 0 ]
T HTTP HEAD:
T Host: host.example.com:38083
T User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
T Accept: */*
T Accept-Language: en,da;q=0.5
T Accept-Encoding: gzip, deflate
T Content-Type: application/json; charset=utf-8
T Authorization: Digest username="rpc_user", realm="monero-rpc", nonce="TxiQqEIvHWWbjks8rvdMRA==", uri="/", algorithm="MD5", response="34638b90a7ae09644c8559fa7e1dc4a4", qop="auth", nc=00000001, cnonce="bd5fd9b093dccaa1"
T Content-Length: 61
T Origin: http://host.example.com
T DNT: 1
T Connection: keep-alive
T Referer: http://host.example.com/test-05/
T Pragma: no-cache
T Cache-Control: no-cache
T
I HTTP [client.ip.addr] POST /json_rpc
I [client.ip.addr:34239 INC] Calling RPC method get_version
D /json_rpc[get_version] processed with 0/0/0ms
T HTTP_RESPONSE_HEAD: <<
T HTTP/1.1 200 Ok
T Server: Epee-based
T Content-Length: 104
T Content-Type: application/json
T Last-Modified: Thu, 19 Mar 2020 14:55:14 GMT
T Accept-Ranges: bytes
T Access-Control-Allow-Origin: http://host.example.com
T Access-Control-Expose-Headers: www-authenticate
T Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS
T
T Throttle throttle_speed_out: packet of ~434b (from 434 b) Speed AVG= 0[w=1] 0[w=1] / Limit=16 KiB/sec [1099 0 0 0 0 0 0 0 0 0 ]
D do_send_chunk() NOW SENSD: packet=434 B
T Setting 00:05:00 expiry
T Setting 00:05:00 expiry
T [client.ip.addr:34239 INC] [sock 9] Async send calledback 434
T [sock 8] Some not success at read: End of file:2
T [sock 8] peer closed connection
T Closed connection from host client.ip.addr: 2
T [sock 8] Socket destroyed
D Destructing connection #6 to client.ip.addr
T [sock 9] Some not success at read: End of file:2
T [sock 9] peer closed connection
T Closed connection from host client.ip.addr: 1
T [sock 9] Socket destroyed
D Destructing connection #7 to client.ip.addr
Certificate trusted by Firefox:
The code that does the talking:
function httpClient (config, callback) {
let xhr = new XMLHttpRequest();
xhr.onload = () => {
//Step 4: Receive original request data
if (xhr.status == 200) {
callback({
result: xhr.status,
message: xhr.statusText,
response: xhr.responseText
})
} else {
callback({
result: xhr.status,
message: xhr.statusText,
response: xhr.responseText
})
}
};
xhr.onerror = (e) => {
console.log("Error:", e);
console.log({
result: xhr.status,
message: xhr.statusText,
response: xhr.responseText
});
callback({
result: xhr.status,
message: xhr.statusText,
response: 'Some error ocurred during this request.'
})
};
xhr.onreadystatechange = (e) => {
if (xhr.readyState >= 2 && xhr.status == 401) {
console.log("readyState:", xhr.readyState, xhr.status, xhr.statusText);
let authHeader = xhr.getResponseHeader('www-authenticate');
let authObject = parseResponseHeader(authHeader);
let authResponse = buildAuthorizeHeader(config.auth, authObject);
config.headers["Authorization"] = authResponse;
xhr.abort();
httpClient(config, callback);
}
else
console.log("readyState:", xhr.readyState, xhr.status, xhr.statusText);
};
config.protocol = config.protocol.replace(/\:$/, '');
let encodedURI = encodeURI(config.protocol + '://' + config.url);
xhr.open(config.method, encodedURI, true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
for (let [key, value] of Object.entries(config.headers)) {
xhr.setRequestHeader(key, value);
}
xhr.withCredentials = false;
if (config.method.toUpperCase() == 'POST' && typeof config.data == "object" ) {
xhr.send(JSON.stringify(config.data))
} else {
xhr.send()
}
const buildAuthorizeHeader = (config, tokensObj ) => {
tokensObj.headers["cnonce"] = 'bd5fd9b093dccaa1';
tokensObj.headers["nc"] = '00000001';
tokensObj.headers["algorithm"] = 'MD5';
tokensObj.headers["method"] = 'POST';
tokensObj.headers["domain"] = '/';
let HA1 = CryptoJS.MD5(config.user + ':' + tokensObj.headers["realm"] + ':' + config.pass).toString();
let HA2 = CryptoJS.MD5(tokensObj.headers["method"] + ':' + tokensObj.headers["domain"]).toString();
let authResponse = CryptoJS.MD5(HA1 +
':' + tokensObj.headers["nonce"] +
':' + tokensObj.headers["nc"] +
':' + tokensObj.headers["cnonce"] +
':' + tokensObj.headers["qop"] +
':' + HA2).toString();
let responseContentHeader = 'Digest username="' + config.user + '"' +
', realm="' + tokensObj.headers["realm"] + '"' +
', nonce="' + tokensObj.headers["nonce"] + '"' +
', uri="' + tokensObj.headers["domain"] + '"' +
', algorithm="' + tokensObj.headers["algorithm"] + '"' +
', response="' + authResponse + '"' +
', qop="' + tokensObj.headers["qop"] + '"' +
', nc=' + tokensObj.headers["nc"] +
', cnonce="' + tokensObj.headers["cnonce"] + '"';
return responseContentHeader;
}
const parseResponseHeader = (h) => {
let auth = {
headers : {}
};
var scre = /^\w+/;
var scheme = scre.exec(h);
auth.scheme = scheme[0];
var nvre = /(\w+)=['"]([^'"]+)['"]/g;
var pairs = h.match(nvre);
var vre = /(\w+)=['"]([^'"]+)['"]/;
var i = 0;
for (; i < pairs.length; i++) {
var v = vre.exec(pairs[i]);
if (v) {
auth.headers[v[1]] = v[2];
}
}
return auth;
}
}
--rpc-access-control-origins
to*
orsome.ip.address
?--rpc-access-control-origins 'http://site1.example.com,https://site1.example.com,http://site2.example.com,https://site2.example.com'
Edit: There's no way of knowing who's accessing the web-site.*
means any host. If the js file (calling the wallet RPC) was hosted athttps://example.com/site.js
, you would need to run the wallet RPC with--rpc-access-control-origins example.com
or--rpc-access-control-origins *
.--rpc-access-control-origins
list the websites hosting the js. Theclient.ip.address
in the log is the browser accessing the website.--rpc-access-control-origins '*'
makes no difference. Same output in the log.