- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写后端代码以在 Node.JS 中验证来自 Google 的 SafetyNet API 的 JWS。我很惊讶没有为此找到现成可用的模块,所以我开始使用可用库查看 JWS 的一些简单验证:
首先,Google 表示需要执行以下步骤:
- Extract the SSL certificate chain from the JWS message.
- Validate the SSL certificate chain and use SSL hostname matching to verify that the leaf certificate was issued to the hostname attest.android.com.
- Use the certificate to verify the signature of the JWS message.
- Check the data of the JWS message to make sure it matches the data within your original request. In particular, make sure that the timestamp has been validated and that the nonce, package name, and hashes of the app's signing certificate(s) match the expected values.
(来自 https://developer.android.com/training/safetynet/attestation#verify-attestation-response)
我找到了 node-jose它提供了一个简单的接口(interface)来验证 JWS,并且它有一个允许嵌入 key 的选项。我试图准确了解此过程的作用,以及它是否足以验证 JWS 的真实性?
const {JWS} = require('node-jose');
const result = await JWS.createVerify({allowEmbeddedKey: true}).verify(jws);
if (result.key.kid === 'attest.android.com') {
// Are we good to go or do we manually need to verify the certificate chain further?
}
使用嵌入式 key 是否确实使用根 CA 和针对证书的签名验证了嵌入式证书链 x5c
?或者我是否需要明确地从谷歌获取公钥来单独验证证书?
然后,一个有点相关的问题涉及 Google 用于执行此验证的 API:有一个 API https://www.googleapis.com/androidcheck/v1/attestations/verify?key=...
执行此确切操作,但它似乎已从 Google 的文档中删除,并且只能在过时的文章和有关 SafetyNet 的 SO 答案中找到引用,例如 this one这似乎表明此 API 仅用于测试,在生产中您应该自己执行证书验证。有谁知道这个 API 是否适合生产使用?如果每个人都打算手动验证 JWS,我觉得有点奇怪 Google 不会提供更多的文档和代码示例,因为这个过程很容易出错,而且错误可能会造成严重的影响?到目前为止,我只找到了一些 Java 中的第 3 方示例,但没有来自 Google 的服务器端代码示例。
最佳答案
这是 the steps您需要按照 Google 的建议执行。
当然可以随意浏览所有引用链接,以便更好地理解该过程。请查看此处使用的每个库函数,了解它们在做什么,以及这是否正是您希望它们做的。我已经编写了伪代码来解释这些步骤。您可能必须在示例证明 token 上运行它们以测试它们并相应地更改一些内容。
最好在一个地方查看 SafetyNet 的整个 Node 实现。
// following steps should be performed
// 1. decode the JWS
// 2. the source of the first certificate in x5c array of jws header
// should be attest.google.com
// 3. to make sure if the JWS was not tampered with, validate the signature of JWS (how signature verification is done is explained in the reference links)
// with the certificate whose source we validated
// 4. if the signature was valid, we need to know if the certificate was valid by
// explicitly checking the certificate chain
// 5. Validate the payload by matching the package name, apkCertificateDigest
// and nonce value (apkCertificateDigest is base64 encoding of the hash of signing app's certificate)
// 6. and now you can trust the ctsProfileMatch and BasicIntegrity flags
// let's see some code in node, though this will not run as-is,
// it provides an outline on how to do it and which functions to consider when implementing
const pki = require('node-forge').pki;
const jws = require('jws');
const pem = require("pem");
const forge = require('node-forge');
const signedAttestation = "Your signed attestation here";
function deviceAttestationCheck(signedAttestation) {
// 1. decode the jws
const decodedJws = jws.decode(signedAttestation);
const payload = JSON.parse(decodedJws.payload);
// convert the certificate received in the x5c array into valid certificates by adding
// '-----BEGIN CERTIFICATE-----\n' and '-----END CERTIFICATE-----'
// at the start and end respectively for each certificate in the array
// and by adding '\n' at every 64 char
// you'll have to write your own function to do the simple string reformatting
// get the x5c certificate array
const x5cArray = decodedJws.header.x5c;
updatedX5cArray = doTheReformatting(x5cArray);
// 2. verify the source to be attest.google.com
certToVerify = updatedX5cArray[0];
const details = pem.readCertificateInfo(certToVerify);
// check if details.commanName === "attest.google.com"
const certs = updatedX5cArray.map((cert) => pki.certificateFromPem(cert));
// 3. Verify the signature with the certificate that we received
// the first element of the certificate(certs array) is the one that was issued to us, so we should use that to verify the signature
const isSignatureValid = jws.verify(signedAttestation, 'RS256', certs[0]);
// 4. to be sure if the certificate we used to verify the signature is the valid one, we should validate the certificate chain
const gsr2Reformatted = doTheReformatting(gsr2);
const rootCert = pki.certificateFromPem(gsr2Reformatted);
const caStore = pki.createCaStore([rootCert]);
// NOTE: this pki implementation does not check for certificate revocation list, which is something that you'll need to do separately
const isChainValid = pki.verifyCertificateChain(caStore, certs);
// 5. now we can validate the payload
// check the timestamps, to be within certain time say 1 hour
// check nonce value, to contain the data that you expect, refer links below
// check apkPackageName to be your app's package name
// check apkCertificateDigestSha256 to be from your app - quick tip -look at the function below on how to generate this
// finally you can trust the ctsProfileMatch - true/false depending on strict security need and basicIntegrity - true, minimum to check
}
// this function takes your signing certificate(should be of the form '----BEGIN CERT....data...---END CERT...') and converts into the SHA256 digest in hex, which looks like - 92:8H:N9:84:YT:94:8N.....
// we need to convert this hex digest to base64
// 1. 92:8H:N9:84:YT:94:8N.....
// 2. 928hn984yt948n - remove the colon and toLowerCase
// 3. encode it in base64
function certificateToSha256DigestHex(certPem) {
const cert = pki.certificateFromPem(certPem);
const der = forge.asn1.toDer(pki.certificateToAsn1(cert)).getBytes();
const m = forge.md.sha256.create();
m.start();
m.update(der);
const fingerprint = m.digest()
.toHex()
.match(/.{2}/g)
.join(':')
.toUpperCase();
return fingerprint
}
// 92:8H:N9:84:YT:94:8N => 928hn984yt948n
function stringToHex(sha256string) {
return sha256string.split(":").join('').toLowerCase();
}
// this is what google sends you in apkCertificateDigestSha256 array
// 928hn984yt948n => "OIHf9wjfjkjf9fj0a="
function hexToBase64(hexString) {
return Buffer.from(hexString, 'hex').toString('base64')
}
所有对我有帮助的文章:
关于node.js - 可靠地验证 JWS 证书链和域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60434676/
我阅读了可以找到的 JSON Web 签名规范 here .该规范为 JSON Web 签名定义了两种序列化表示。一种是 JWS Compact Serialization,另一种是 JWS JSON
我正在研究 WSDL 和 JAX-WS,这就是我遇到这个问题的地方。当我在 JAX-WS 中编写服务接口(interface)时,如下所示: @WebService @SOAPBinding(styl
我正在尝试使用 Certbot 为我的 IIS 服务器获取证书。但我不断收到此错误: [31mAn unexpected error occurred:[0m [31mThe JWS was sign
我有一个很大的 Java applet(大约 7 MB)。这是一个古老而庞大的项目,由几个 (7) 个较小的项目组成,所有项目都使用“fatjar”捆绑在一个 jar 中。由于 applet 是一项旧
如何查看 JWS 应用程序堆栈跟踪? 最佳答案 如果您指的是 Java Web Start,那么您需要进入 Java 设置并打开控制台。 (将其设置为“始终”显示。)下次单击 JNLP 时,控制台将启
我正在部署一个需要一些外部库才能运行的 swing 客户端。我如何才能通过下载它们在 JNLP 中?是否有使它们可用的配置或可以放置它们的文件夹? 最佳答案 如上所述here ,必须可以使用 href
我有一个使用许多数据文件的 swing 应用程序,这些数据文件会不时更改。如何将这些数据文件加载到客户端计算机上?有什么方法可以创建类似结构的文件夹并运行批处理文件等吗?任何帮助表示赞赏。 最佳答案
我的 JWS 应用程序 jar 已签名1,当我启动该证书时,它不会要求任何东西,只是抛出一个异常,说明您的应用程序已被阻止。 如果我安装该证书它就可以工作,但是我如何强制我的应用程序给出一条消息来安装
我已获得可信机构颁发的证书(已获得 .pfx 文件)。 我像这样用 jarsigner 签署了我所有的 .jar 文件: jarsigner -storetype pkcs12 -keystore m
是否可以将 Tomcat 与带有 Java WebStart 的 Spring 应用程序捆绑在一起?如何捆绑? 最佳答案 Jetty提供对嵌入的支持,然后您将在 jnlp 中声明 jar 文件,并从主
是否可以在 HTML 中嵌入小程序,以便将其显示在浏览器窗口中,然后通过 JNLP 文件通过 Java Web Start 启动,而不是使用浏览器的 Java 插件?如果是这样,这是如何完成的? 我只
我确实写了一个简单的 java web 服务(使用 javax jws)。我正在尝试将此服务部署到 openshift 的 Jboss 服务器中。当我尝试访问该服务时,我收到了上述异常。 Java 服
我正在尝试将一个简单的 java servlet 部署到 Tomcat,它使用部署到本地主机上同一个 Tomcat 的 Web 服务。我正在 Netbeans 中处理 Maven 项目。 servle
我正在编写后端代码以在 Node.JS 中验证来自 Google 的 SafetyNet API 的 JWS。我很惊讶没有为此找到现成可用的模块,所以我开始使用可用库查看 JWS 的一些简单验证: 首
刚刚了解 JOSE,我知道 JWE 用于加密,而 JWS 用于签名。我似乎无法找到既加密又签名的有效负载的示例。 让我们假设我有一个有效载荷 hello world .做这样的事情是正确的吗? JWS
我不明白为什么存在 JWS 不 protected header 。 对于某些上下文:JWS 不 protected header 包含不受完整性保护的参数,并且只能与 JSON 序列化一起使用每个签
我在AWS-EKS中运行我的应用程序,而我的Jenkins实例尚未容器化。为了部署我们的应用程序,我们在Jenkins Pipeline中使用kubectl命令。我想知道通过Jenkins部署Kube
我有一个使用 swing-layout 的旧应用程序,我必须通过 java webstart 使其可用。它从 netbeans 运行良好,但如果我使用 jws 启动它,我会收到此错误: excepti
我在确定如何使用 Java Web Start 程序写入文件时遇到一些问题,我想将文件写入描述已上传到云服务器的文件的服务器。我还希望从客户端发送文件名和路径等数据,以便我可以在用户和云存储设施之间创
为什么我的 JWS 应用程序不响应 Swing 按钮操作? 我有一个在 Eclipse 中创建的程序。它收集有关连接到本地网络的设备的信息并将其显示在 JTable 中。在环境中它执行得很好 befo
我是一名优秀的程序员,十分优秀!