我正在尝试使用Varnish VCL在Fastly CDN上设置基于令牌的身份验证,并在此处使用此示例VCL代码片段生成和验证JWT令牌-
sub vcl_recv {
#FASTLY recv
if (req.request != "HEAD" && req.request != "GET" && req.request != "FASTLYPURGE") {
return(pass);
}
// Generate synth
if(req.url ~ "generate") {
error 901;
}
// Validate token
if(req.url ~ "validate") {
// Ensure token exists and parse into regex
if (req.http.X-JWT !~ "^([a-zA-Z0-9\-_]+)?\.([a-zA-Z0-9\-_]+)?\.([a-zA-Z0-9\-_]+)?$") {
// Forbidden
error 403 "Forbidden";
}
// Extract token header, payload and signature
set req.http.X-JWT-Header = re.group.1;
set req.http.X-JWT-Payload = re.group.2;
set req.http.X-JWT-Signature = digest.base64url_nopad_decode(re.group.3);
set req.http.X-JWT-Valid-Signature = digest.hmac_sha256("SupSecretStr",
req.http.X-JWT-Header "." req.http.X-JWT-Payload);
// Validate signature
if(digest.secure_is_equal(req.http.X-JWT-Signature, req.http.X-JWT-Valid-Signature)) {
// Decode payload
set req.http.X-JWT-Payload = digest.base64url_nopad_decode(req.http.X-JWT-Payload);
set req.http.X-JWT-Expires = regsub(req.http.X-JWT-Payload, {"^.*?"exp"\s*?:\s*?([0-9]+).*?$"}, "\1");
// Validate expiration
if (time.is_after(now, std.integer2time(std.atoi(req.http.X-JWT-Expires)))) {
// Unauthorized
synthetic {"{"sign":""} req.http.X-JWT-Signature {"","header":""} req.http.X-JWT-Header {"","payload":""} req.http.X-JWT-Payload {"","valid": ""} req.http.X-JWT-Valid-Signature {""}"};
return(deliver);
}
// OK
synthetic {"{"header2":""} req.http.X-JWT-Header {"","payload":""} req.http.X-JWT-Payload {"","sign":""} req.http.X-JWT-Signature {"","valid": ""} req.http.X-JWT-Valid-Signature {""}"};
return(deliver);
} else {
// Forbidden
synthetic {"{"header3":""} req.http.X-JWT-Header {"","payload":""} req.http.X-JWT-Payload {"","sign":""} req.http.X-JWT-Signature {"","valid": ""} req.http.X-JWT-Valid-Signature {""}"};
return(deliver);
}
}
return(lookup);
}
sub vcl_error {
#FASTLY error
// Generate JWT token
if (obj.status == 901) {
set obj.status = 200;
set obj.response = "OK";
set obj.http.Content-Type = "application/json";
set obj.http.X-UUID = randomstr(8, "0123456789abcdef") "-" randomstr(4, "0123456789abcdef") "-4" randomstr(3, "0123456789abcdef") "-" randomstr(1, "89ab") randomstr(3, "0123456789abcdef") "-" randomstr(12, "0123456789abcdef");
set obj.http.X-JWT-Issued = now.sec;
set obj.http.X-JWT-Expires = strftime({"%s"}, time.add(now, 3600s));
set obj.http.X-JWT-Header = digest.base64url_nopad({"{"alg":"HS256","typ":"JWT""}{"}"});
set obj.http.X-JWT-Payload = digest.base64url_nopad({"{"sub":""} obj.http.X-UUID {"","exp":"} obj.http.X-JWT-Expires {","iat":"} obj.http.X-JWT-Issued {","iss":"Fastly""}{"}"});
set obj.http.X-JWT-Signature = digest.base64url_nopad(digest.hmac_sha256("SupSecretStr", obj.http.X-JWT-Header "." obj.http.X-JWT-Payload));
set obj.http.X-JWT = obj.http.X-JWT-Header "." obj.http.X-JWT-Payload "." obj.http.X-JWT-Signature;
unset obj.http.X-UUID;
unset obj.http.X-JWT-Issued;
unset obj.http.X-JWT-Expires;
unset obj.http.X-JWT-Header;
unset obj.http.X-JWT-payload;
unset obj.http.X-JWT-Signature;
synthetic {"{"payload":""} obj.http.X-JWT-Payload {"","header":""} obj.http.X-JWT-Header {"","sign":""} obj.http.X-JWT-Signatre {"","token": ""} obj.http.X-JWT {""}"};
return(deliver);
}
// Valid token
if (obj.status == 902) {
set obj.status = 200;
set obj.response = "OK";
set obj.http.Content-Type = "application/json";
synthetic {"{ "token": ""} req.http.X-JWT {"" }"};
return(deliver);
}
}
现在,当我尝试编译它时,它会返回-
Syntax error: Unterminated _short-string_
at: (input Line 106 Pos 197)
synthetic {"{"sign":""} req.http.X-JWT-Signature {"","header":""} req.http.X-JWT-Header {"","payload":""} req.http.X-JWT-Payload {"","valid": ""} req.http.X-JWT-Valid-Signature {""}"};
在合成块期间,我似乎无法以某种方式正确地转义这些值。
我试图在vcl_recv子例程中添加此合成块的唯一原因是,我想测试摘要如何生成JWT令牌并对其进行验证,并且我想在服务器端创建类似的JWT令牌。 Node.Js,所以我试图输出令牌的不同中间部分进行调试。
我对Varnish的语法和语义不太熟悉,但我仍在寻求帮助,以查找有关此Schedule子例程的任何文档,但到目前为止没有找到任何文档。
所以,任何人都可以帮忙解决此问题,并让vcl_recv,vcl_error在json响应中插值不同的中间值。
我尝试使用一些基于Node.Js的base64 url解码库来解码返回的令牌部分,并且能够解码标头和有效负载部分,但无法从Node.Js生成签名部分。那么,有人可以建议node.js或任何javascript库中的base64url_nopad()等效吗?
对于hmac_256加密部分,我们试图使用加密库并创建一个类似crypto.createHmac('sha256','SupSecretStr')。update()。digest('hex')的hmac。但是我认为js中所有base64编码的url库都返回填充的url,这就是为什么此hmac 256摘要的base64编码的部分与用清漆生成的部分不匹配的原因
答案 0 :(得分:1)
我的语法着色工具告诉我与错误消息几乎相同的东西:您搞砸了引号:-)
您的最后一个块{""}"};
是打开引号({"
),立即关闭它们("}
),然后打开简单的引号"
,换行符在您之前关闭它们。
要解决此问题,只需在json的最后引号后面加上一个空格:{"" }"};