OpenID - 生成签名

发布于 2024-11-06 21:18:28 字数 3228 浏览 0 评论 0原文

我一直在编写自己的 Open ID RP 实现(是的,我知道已经构建了很多,我这样做是为了“乐趣”)。一切工作正常,直到我进入验证步骤并计算哈希值并将其与我在肯定断言中从 OP 获得的 sig 进行比较。

我已经仔细阅读了规范,但有一些事情我不清楚:

  1. 我是否只包含 openid 命名空间中的键值对或 openid.signed 列表中的所有内容? 6.1 听起来我应该只使用 openid 。即使我在 openid.signed (ax) 中还有其他一些东西,

  2. 最后一个键值对后面是否应该有一个换行符?

  3. 我假设这些值应该进行 url 编码(以免值中包含冒号)。如果是这样,我还假设十六进制值(例如%3D)应该是大写的。我在 OAuth 1.0 实现中遇到了这个问题,因为 .NET 内置的 URL 编码使用小写的十六进制字母。

我相当确定编码和算法都很好,但我的基本字符串已关闭。这是一个完全未更改的示例版本,我无法开始工作:

我从OP返回的查询字符串带有肯定的断言: openid.ns=http://specs.openid.net/auth/2.0&openid.mode=id_res&openid.op_endpoint=https://www.google.com/accounts/o8/ud&openid。 response_nonce=2011-05-13T08:18:42ZBHyiLFGyNT-SqQ&openid.return_to=http://mysite.com/Account/Login.aspx&openid.assoc_handle=AOQobUc4P9MWC3faGcMkfTb2U10KfGQ-6cm9L4pLDQmeoY2DE6XRGtN0& amp;openid.signed=op_endpoint,claimed_id,身份, return_to,response_nonce,assoc_handle,ns.ext1,ext1.mode,ext1.type.firstname,ext1.value.firstname,ext1.type.email,ext1.value.email,ext1.type.lastname,ext1.value.lastname& openid.sig=KSXw+bv7sLlQyUIflA3Jzx5VoPk=&openid.identity=https://www.google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4&openid.claimed_id=https://www.google.com/accounts/ o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4&openid.ns.ext1=http://openid.net/srv/ax/1.0&openid.ext1.mode=fetch_response&openid.ext1.type.firstname=http://axschema .org/namePerson/first&openid.ext1.value.firstname=firstname&openid.ext1.type.email=http://schema.openid.net/contact/email&[电子邮件保护编辑]&openid.ext1.type.lastname=http://axschema.org/namePerson/last&openid .ext1.value.lastname=lastname

我使用该查询字符串构建的基本字符串: op_endpoint:https://www.google.com/accounts/o8/ud\nclaimed_id:https://www.google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4\n身份:https://www .google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4\nreturn_to:http://mysite.com/Account/Login.aspx\nresponse_nonce:2011-05-13T08:18:42ZBHyiLFGyNT-SqQ\nassoc_handle:AOQobUc4P9MWC3faGcMkfTb2U10KfGQ-6cm9L4pLDQmeoY2DE6XRGtN0 \nns.ext1:http://openid.net/srv/ax/1.0\next1.mode:fetch_response\next1.type.firstname:http://axschema.org/namePerson/first\next1.value.firstname:firstname \next1.type.email:http://schema.openid.net/contact/email\next1.value.email:[电子邮件受保护]\next1.type.lastname:http://axschema.org/namePerson/last\next1.value.lastname:lastname\n

Mac 密钥由关联请求返回: U/1wUBAU2aYIR+2eIsugXyEOpmE=

将所有这些与 HMAC-SHA1 结合使用,我得到的哈希值是: 9HMRL4je44Oz90s1f8pw5qpZ8HQ=

但是从openid.sig可以看到,应该是 KSXw+bv7sLlQyUIflA3Jzx5VoPk=

我是否错误地制定了基本字符串?我计算哈希值是否错误?这么“简单”的事情怎么需要这么长时间才能正确实施?

I've been writing my own implementation of Open ID RP (yes I know there are plenty already built, I'm doing it for "fun"). Everything works fine until I am in the verification step and calculate the hash and compare it against the sig I got from the OP in the positive assertion.

I've read the spec up and down but there are a few things that weren't clear to me:

  1. Do I only include the key value pairs in the openid namespace or everything that's in the list in openid.signed? 6.1 makes it sound like I should only use openid. keys even though I have some other stuff hanging out in openid.signed (ax).

  2. Should the last key value pair be follow by a line break?

  3. I'm assuming the values should be url encoded (as not to have colons in the value). If so, I would also assume the hex values, such as %3D, should be uppercase. I ran into that on an OAuth 1.0 implementation, since .NET's built in URL encoding uses lower case hex letters.

I'm fairly certain the encoding and algorithm are fine but my base string is off. Here is a completely unaltered version of an example which I can't get to work:

Querystring I get back from the OP with the positive assertion:
openid.ns=http://specs.openid.net/auth/2.0&openid.mode=id_res&openid.op_endpoint=https://www.google.com/accounts/o8/ud&openid.response_nonce=2011-05-13T08:18:42ZBHyiLFGyNT-SqQ&openid.return_to=http://mysite.com/Account/Login.aspx&openid.assoc_handle=AOQobUc4P9MWC3faGcMkfTb2U10KfGQ-6cm9L4pLDQmeoY2DE6XRGtN0&openid.signed=op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle,ns.ext1,ext1.mode,ext1.type.firstname,ext1.value.firstname,ext1.type.email,ext1.value.email,ext1.type.lastname,ext1.value.lastname&openid.sig=KSXw+bv7sLlQyUIflA3Jzx5VoPk=&openid.identity=https://www.google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4&openid.claimed_id=https://www.google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4&openid.ns.ext1=http://openid.net/srv/ax/1.0&openid.ext1.mode=fetch_response&openid.ext1.type.firstname=http://axschema.org/namePerson/first&openid.ext1.value.firstname=firstname&openid.ext1.type.email=http://schema.openid.net/contact/email&[email protected]&openid.ext1.type.lastname=http://axschema.org/namePerson/last&openid.ext1.value.lastname=lastname

The base string I built using that querystring:
op_endpoint:https://www.google.com/accounts/o8/ud\nclaimed_id:https://www.google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4\nidentity:https://www.google.com/accounts/o8/id?id=AItOawkDYxJln6LwTAdl0kP8xdMT71SoRufUFA4\nreturn_to:http://mysite.com/Account/Login.aspx\nresponse_nonce:2011-05-13T08:18:42ZBHyiLFGyNT-SqQ\nassoc_handle:AOQobUc4P9MWC3faGcMkfTb2U10KfGQ-6cm9L4pLDQmeoY2DE6XRGtN0\nns.ext1:http://openid.net/srv/ax/1.0\next1.mode:fetch_response\next1.type.firstname:http://axschema.org/namePerson/first\next1.value.firstname:firstname\next1.type.email:http://schema.openid.net/contact/email\next1.value.email:[email protected]\next1.type.lastname:http://axschema.org/namePerson/last\next1.value.lastname:lastname\n

The mac key as returned by the assocation request:
U/1wUBAU2aYIR+2eIsugXyEOpmE=

Using all of this with HMAC-SHA1, the hash I get is:
9HMRL4je44Oz90s1f8pw5qpZ8HQ=

But as you can see from openid.sig, it should be
KSXw+bv7sLlQyUIflA3Jzx5VoPk=

Am I formulating the base string incorrectly? Am I calculating the hash wrong? How is something this "simple" taking so long to implement correctly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

_畞蕅 2024-11-13 21:18:28

我在生成匹配签名时也遇到了问题,最后找到了解决方案。

  1. 正如您所怀疑的,您必须添加来自 openid.ax 命名空间的值,应用与添加不带 openid. 前缀的键/值对相同的规则。如果没有 openid.ax 键,则说明有问题。

  2. 是的,最后一个键/值对后面跟着一个换行符(注意:只有一个 \n)。这在 OpenID 规范中可以更清楚地提到。

  3. 您对 URL 编码的理解是错误的,恰恰相反:这些值必须是 URL 解码。规范中也没有明确说明这一点。不要混淆冒号和分号,不允许有冒号,只能在关键部分,所以这没有问题。

因此,如果您尝试使用此字符串并添加缺少的键/值对,它应该可以工作:

ns:http://specs.openid.net/auth/2.0
op_endpoint:https://www.google.com/accounts/o8/ud
claimed_id:https://www.google.com/accounts/o8/id?id=AItOawlvj7acGYj-NH1kKKl3RswJlLCKpl9LIwk
identity:https://www.google.com/accounts/o8/id?id=AItOawlvj7acGYj-NH1kKKl3RswJlLCKpl9LIwk
return_to:http://mysite.com/Account/Login.aspx
response_nonce:2011-05-12T03:56:09ZoeDC9WFOgOBaAQ
assoc_handle:AOQobUdHugprvbsK2-8NCtS2uBomRDGJQGOKDmqEwxco8Rny47rdZlBp
ns.ext1:http://openid.net/srv/ax/1.0
ext1.mode:fetch_response
ext1.type.firstname:http://axschema.org/namePerson/first
ext1.value.firstname:First
ext1.type.email:http://schema.openid.net/contact/email
ext1.value.email:[email protected]
ext1.type.lastname:http://axschema.org/namePerson/last
ext1.value.lastname:Name

这个小控制台应用程序重新生成签名(使用 HMAC-SHA256),它需要两个参数:

  • 成功 OpenID 身份验证后的完整重定向 URL (包含肯定断言密钥),可以从 Web 浏览器的地址栏复制
  • Base64 编码的 MAC 密钥,如先前关联响应

代码中返回的那样:

using System;

public class OpenIdSignatureVerification {

    public static void Main(string[] args) {
        if (args.Length != 2) {
            Console.Error.WriteLine("Usage: assertion_url mac_key");
            Environment.Exit(1);
        }

        string url = args[0];
        int pos = url.IndexOf('?');
        if (pos == -1) {
            Console.Error.WriteLine("No query string found");
            Environment.Exit(1);
        }
        url = url.Substring(pos + 1);
        Console.WriteLine(String.Format("Query string: {0}", url));

        System.Collections.Generic.Dictionary<string, string> dict = new System.Collections.Generic.Dictionary<string, string>();

        foreach (string part in url.Split('&')) {
            string[] keyValue = part.Split('=');
            if (keyValue.Length != 2) continue;
            dict[keyValue[0]] = System.Web.HttpUtility.UrlDecode(keyValue[1]);
        }

        string hashInput = String.Empty;
        string[] signed = dict["openid.signed"].Replace("%2C", ",").Split(',');
        foreach (string key in signed) hashInput += key + ":" + dict["openid." + key] + "\n";

        string macKey = args[1];

        Console.WriteLine(String.Format("Hash input: {0}\n", hashInput));
        Console.WriteLine(String.Format("MAC Key: {0}", macKey));

        byte[] encodedHashInput = System.Text.Encoding.UTF8.GetBytes(hashInput);

        System.Security.Cryptography.HMACSHA256 signer = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(macKey)); 

        string hashOutput = Convert.ToBase64String(signer.ComputeHash(encodedHashInput));

        Console.WriteLine(String.Format("Signature hash (expected)  : {0}", dict["openid.sig"]));
        Console.WriteLine(String.Format("Signature hash (calculated): {0}", hashOutput));
    }

}

I had also problems generating a matching signature and finally found the solution.

  1. As you already suspected, you have to add the values from the openid.ax namespace applying the same rule of adding the key/value pair without the openid. prefix. If there are no openid.ax keys, then something is wrong.

  2. Yes, the last key/value pair is followed by a newline (attention: only an \n). This could have been mentioned more clearly in the OpenID specification.

  3. You are wrong about the URL encoding, it's exactly the other way around: The values must be URL-decoded. Also this is not explicitly told in the spec. Don't confuse colons and semicolons, you are not allowed to have colons, but only in the key part, so there is no problem about this.

So if you try with this string and add the missing key/value pairs, it should work:

ns:http://specs.openid.net/auth/2.0
op_endpoint:https://www.google.com/accounts/o8/ud
claimed_id:https://www.google.com/accounts/o8/id?id=AItOawlvj7acGYj-NH1kKKl3RswJlLCKpl9LIwk
identity:https://www.google.com/accounts/o8/id?id=AItOawlvj7acGYj-NH1kKKl3RswJlLCKpl9LIwk
return_to:http://mysite.com/Account/Login.aspx
response_nonce:2011-05-12T03:56:09ZoeDC9WFOgOBaAQ
assoc_handle:AOQobUdHugprvbsK2-8NCtS2uBomRDGJQGOKDmqEwxco8Rny47rdZlBp
ns.ext1:http://openid.net/srv/ax/1.0
ext1.mode:fetch_response
ext1.type.firstname:http://axschema.org/namePerson/first
ext1.value.firstname:First
ext1.type.email:http://schema.openid.net/contact/email
ext1.value.email:[email protected]
ext1.type.lastname:http://axschema.org/namePerson/last
ext1.value.lastname:Name

This little console application re-generates the signature (using HMAC-SHA256), it needs two parameters:

  • the complete redirect URL after the successful OpenID authentication (containing the positive assertion keys), can be copied from the web browser's address bar
  • the Base64-encoded MAC key, as returned in the prior association response

Code:

using System;

public class OpenIdSignatureVerification {

    public static void Main(string[] args) {
        if (args.Length != 2) {
            Console.Error.WriteLine("Usage: assertion_url mac_key");
            Environment.Exit(1);
        }

        string url = args[0];
        int pos = url.IndexOf('?');
        if (pos == -1) {
            Console.Error.WriteLine("No query string found");
            Environment.Exit(1);
        }
        url = url.Substring(pos + 1);
        Console.WriteLine(String.Format("Query string: {0}", url));

        System.Collections.Generic.Dictionary<string, string> dict = new System.Collections.Generic.Dictionary<string, string>();

        foreach (string part in url.Split('&')) {
            string[] keyValue = part.Split('=');
            if (keyValue.Length != 2) continue;
            dict[keyValue[0]] = System.Web.HttpUtility.UrlDecode(keyValue[1]);
        }

        string hashInput = String.Empty;
        string[] signed = dict["openid.signed"].Replace("%2C", ",").Split(',');
        foreach (string key in signed) hashInput += key + ":" + dict["openid." + key] + "\n";

        string macKey = args[1];

        Console.WriteLine(String.Format("Hash input: {0}\n", hashInput));
        Console.WriteLine(String.Format("MAC Key: {0}", macKey));

        byte[] encodedHashInput = System.Text.Encoding.UTF8.GetBytes(hashInput);

        System.Security.Cryptography.HMACSHA256 signer = new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(macKey)); 

        string hashOutput = Convert.ToBase64String(signer.ComputeHash(encodedHashInput));

        Console.WriteLine(String.Format("Signature hash (expected)  : {0}", dict["openid.sig"]));
        Console.WriteLine(String.Format("Signature hash (calculated): {0}", hashOutput));
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文