0

我正在尝试使用证明密钥验证请求是否来自 Office 网页版

我已经多次阅读这个资源,但仍然不知道如何在 PHP 中实现它。

我试过下面的代码似乎没有解决问题,我不知道下一步该怎么做。

有人可以给我一个建议吗?

$rsa = new Crypt_RSA();
$modulus = new Math_BigInteger(base64_decode($modulus), 256);
$exponent = new Math_BigInteger(base64_decode($exponent), 256);

$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
$rsa->setPublicKey();
$publicKey = $rsa->getPublicKey();
4

3 回答 3

3

我知道验证 WOPI 证明密钥实现起来相当复杂,而从文档中的解释中提取编程逻辑具有挑战性。不幸的是,我不是 PHP 开发人员。但是,我想分享我的生产 C# 代码以防万一。

private async Task<bool> ValidateWopiProof(HttpContext context)
{
    // Make sure the request has the correct headers
    if (!context.Request.Headers.ContainsKey(WopiRequestHeader.PROOF) ||
        !context.Request.Headers.ContainsKey(WopiRequestHeader.TIME_STAMP))
        return false;

    // TimestampOlderThan20Min
    var timeStamp = long.Parse(context.Request.Headers[WopiRequestHeader.TIME_STAMP].ToString());
    var timeStampDateTime = new DateTime(timeStamp, DateTimeKind.Utc);
    if ((DateTime.UtcNow - timeStampDateTime).TotalMinutes > 20)
        return false;

    // Set the requested proof values
    var requestProof = context.Request.Headers[WopiRequestHeader.PROOF];
    var requestProofOld = String.Empty;
    if (context.Request.Headers.ContainsKey(WopiRequestHeader.PROOF_OLD))
        requestProofOld = context.Request.Headers[WopiRequestHeader.PROOF_OLD];

    // Get the WOPI proof info from Wopi discovery
    var wopiProofPublicKey = await _wopiDiscovery.GetWopiProof();

    // Encode the values into bytes
    var accessTokenBytes = Encoding.UTF8.GetBytes(context.Request.Query["access_token"].ToString());

    var hostUrl = GetAbsolouteUrl(context);
    var hostUrlBytes = Encoding.UTF8.GetBytes(hostUrl.ToUpperInvariant());

    var timeStampBytes = BitConverter.GetBytes(Convert.ToInt64(context.Request.Headers[WopiRequestHeader.TIME_STAMP])).Reverse().ToArray();

    // Build expected proof
    List<byte> expected = new List<byte>(
        4 + accessTokenBytes.Length +
        4 + hostUrlBytes.Length +
        4 + timeStampBytes.Length);

    // Add the values to the expected variable
    expected.AddRange(BitConverter.GetBytes(accessTokenBytes.Length).Reverse().ToArray());
    expected.AddRange(accessTokenBytes);
    expected.AddRange(BitConverter.GetBytes(hostUrlBytes.Length).Reverse().ToArray());
    expected.AddRange(hostUrlBytes);
    expected.AddRange(BitConverter.GetBytes(timeStampBytes.Length).Reverse().ToArray());
    expected.AddRange(timeStampBytes);
    byte[] expectedBytes = expected.ToArray();

    return (VerifyProofKeys(expectedBytes, requestProof, wopiProofPublicKey.Value) ||
        VerifyProofKeys(expectedBytes, requestProofOld, wopiProofPublicKey.Value) ||
        VerifyProofKeys(expectedBytes, requestProof, wopiProofPublicKey.OldValue));
}

private string GetAbsolouteUrl(HttpContext context)
{
    var url = $"{_wopiUrlService.ApiAddress.TrimEnd('/')}{context.Request.Path}{context.Request.QueryString}";
    return url.Replace(":44300", "").Replace(":443", "");
}

private bool VerifyProofKeys(byte[] expectedProof, string proofFromRequest, string discoPublicKey)
{
    using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider())
    {
        try
        {
            rsaProvider.ImportCspBlob(Convert.FromBase64String(discoPublicKey));
            return rsaProvider.VerifyData(expectedProof, "SHA256", Convert.FromBase64String(proofFromRequest));
        }
        catch (FormatException)
        {
            return false;
        }
        catch (CryptographicException)
        {
            return false;
        }
    }
}

此实现遵循文档规范。对于方法_wopiDiscovery.GetWopiProof(),我只是从Wopi Discoveryproof-key获得部分。

在 wopi 发现中获取 wopi 证明密钥.

于 2020-08-14T04:15:28.733 回答
0

你可以在 PHP 中找到一个 WOPI 证明验证器,在这个包中:https ://github.com/Champs-Libres/wopi-lib/

这个包是在 PHP 应用程序中集成 WOPI 协议的助手。

它包含一个开箱即用的 WOPI 证明验证器服务。

于 2021-09-06T06:25:53.553 回答
0

@Rachanee 您的解决方案有效吗?我有相同的代码,但验证失败。

于 2020-11-01T12:53:12.403 回答