Node.js 如何维护Google的公钥缓存';s OpenID连接发现文档
我正在进行Node.js服务器端验证,验证从跨源ajax客户端接收的json web令牌。据推测,令牌是由以下状态生成的: 要使用Google的OpenID Connect服务,您应该将其硬编码到应用程序中。应用程序获取文档,然后根据需要从中检索端点URI 您可以通过缓存发现文档中的值来避免HTTP往返。使用标准HTTP缓存头,应遵守这些头 资料来源: 我编写了以下函数,该函数使用request.js获取密钥,并使用moment.js向存储缓存密钥的Node.js 如何维护Google的公钥缓存';s OpenID连接发现文档,node.js,caching,google-openid,Node.js,Caching,Google Openid,我正在进行Node.js服务器端验证,验证从跨源ajax客户端接收的json web令牌。据推测,令牌是由以下状态生成的: 要使用Google的OpenID Connect服务,您应该将其硬编码到应用程序中。应用程序获取文档,然后根据需要从中检索端点URI 您可以通过缓存发现文档中的值来避免HTTP往返。使用标准HTTP缓存头,应遵守这些头 资料来源: 我编写了以下函数,该函数使用request.js获取密钥,并使用moment.js向存储缓存密钥的keyCache字典添加一些时间戳属性。此函数
keyCache
字典添加一些时间戳属性。此函数在服务器启动时调用
function cacheWellKnownKeys(uri) {
var openid = 'https://accounts.google.com/.well-known/openid-configuration';
// get the well known config from google
request(openid, function(err, res, body) {
var config = JSON.parse(body);
var jwks_uri = config.jwks_uri;
var timestamp = moment();
// get the public json web keys
request(jwks_uri, function(err, res, body) {
keyCache.keys = JSON.parse(body).keys;
keyCache.lastUpdate = timestamp;
keyCache.timeToLive = timestamp.add(12, 'hours');
});
});
}
在成功缓存密钥之后,我现在关心的是如何随着时间的推移有效地维护缓存
由于谷歌很少更改其公钥(每天一次),因此您可以缓存它们,并且在绝大多数情况下执行本地验证
资料来源:
由于谷歌每天都在更换公钥,我对keyCache
的timestamp
和timeToLive
属性的想法是做两件事之一:
这似乎是一种可行的工作算法,直到我考虑到无效令牌请求的攻击,导致在试图更新高速缓存时,反复访问熟知的配置和公钥。
也许有更好的方法可以减少网络开销。上面第一句话中的这一行可能与开发更高效的解决方案有关,但我不确定该怎么办:使用了标准HTTP缓存头,应该遵守。
我想我的问题真的只是这个
我应该利用谷歌发现文档中的HTTP缓存头来开发更高效的缓存解决方案吗?如何工作?具有属性jwks_uri
,它是另一个带有公钥的文档的网址。这另一份文件是谷歌提到的,他们说
使用标准HTTP缓存头,应遵守这些头
对该地址的HTTP HEAD请求显示以下标头:
HTTP/1.1 200 OK
Expires: Wed, 25 Jan 2017 02:39:32 GMT
Date: Tue, 24 Jan 2017 21:08:42 GMT
Vary: Origin, X-Origin
Content-Type: application/json; charset=UTF-8
X-Content-Type-Options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
Content-Length: 1472
Server: GSE
Cache-Control: public, max-age=19850, must-revalidate, no-transform
Age: 10770
Alt-Svc: quic=":443"; ma=2592000; v="35,34"
X-Firefox-Spdy: h2
从request.js生成的响应对象以编程方式访问这些头字段,并从中解析最大年龄值,如下所示:
var cacheControl = res.headers['cache-control'];
var values = cacheControl.split(',');
var maxAge = parseInt(values[1].split('=')[1]);
最大值以秒为单位测量。然后,我们的想法是基于maxAge(毫秒转换为1000倍)设置一个超时,并在每次超时完成时递归刷新缓存。这解决了在每次无效授权尝试时刷新缓存的问题,并且您可以删除正在使用moment.js进行的时间戳操作
我建议使用以下函数来处理这些已知密钥的缓存
var keyCache = {};
/**
* Caches Google's well known public keys
*/
function cacheWellKnownKeys() {
var wellKnown= 'https://accounts.google.com/.well-known/openid-configuration';
// get the well known config from google
request(wellKnown, function(err, res, body) {
var config = JSON.parse(body);
var address = config.jwks_uri;
// get the public json web keys
request(address, function(err, res, body) {
keyCache.keys = JSON.parse(body).keys;
// example cache-control header:
// public, max-age=24497, must-revalidate, no-transform
var cacheControl = res.headers['cache-control'];
var values = cacheControl.split(',');
var maxAge = parseInt(values[1].split('=')[1]);
// update the key cache when the max age expires
setTimeout(cacheWellKnownKeys, maxAge * 1000);
});
});
}