【问题标题】:pubnub, how to identify the sender?pubnub,如何识别发件人?
【发布时间】:2015-06-09 18:26:50
【问题描述】:

当收到来自 pubnub 的消息时,没有关于发件人的信息。如何知道它是来自 visitorA 还是 visitorB 的消息?网络上有一些例子,发件人在消息中发送他的姓名,但如何知道他没有欺骗他人的身份?

这里是一个聊天界面的例子:

<html>
  <body>
    <form id="message_form">
      <input id="message_input" type="text"/>
    </form>
    <div id="chat"></div>
    <script src="http://cdn.pubnub.com/pubnub-3.7.1.min.js"></script>
    <script>
      var pubnub = PUBNUB.init({
        publish_key: 'demo',
        subscribe_key: 'demo'
      });

      pubnub.subscribe({
        channel: 'chat',
        message: function(message){
          var div = document.createElement("div");
          div.textContent = message;
          var chat = document.getElementById("chat");
          chat.appendChild(div);
        }
      });

      var form = document.getElementById("message_form");
      form.onsubmit = function(e) {
        var input = document.getElementById("message_input");
        pubnub.publish({
          channel: 'chat',
          message: input.value
        });
        input.value = '';
        e.preventDefault();
      };
    </script>
  </body>
</html>

【问题讨论】:

    标签: javascript pubnub


    【解决方案1】:

    聊天用户识别

    您可以通过创建唯一 ID 以及附加到聊天对话的消息负载的 名称识别发件人。这类似于 IRC 策略,但更简单一些。

    var user_id      = PUBNUB.uuid();
    var user_name    = name.value;
    var user_message = input.vaule;
    

    这是一个完整的示例,其中包含用于用户名输入的 HTML 元素。另请注意,我添加了一个 safe_text() 方法来防止 XSS 攻击。

    <form id="message_form">
      Name: <input id="name_input" value="John" type="text"/><br>
      Message: <input id="message_input" value="Hi" type="text"/><br>
      <input type="submit" value="send">
    </form>
    <div id="chat"></div>
    <script src="http://cdn.pubnub.com/pubnub-dev.js"></script>
    <script>
      var userid = PUBNUB.uuid();
      var pubnub  = PUBNUB({
        publish_key   : 'demo',
        subscribe_key : 'demo',
        uuid          : userid
      });
    
      function safe_text(text) {
        return (''+text).replace( /[<>]/g, '' );
      }
      pubnub.subscribe({
        channel: 'chat',
        message: function(message){
          var div = document.createElement("div");
          div.textContent =
            safe_text(message.name) + ": " +
            safe_text(message.text);
    
          var chat = document.getElementById("chat");
          chat.appendChild(div);
        }
      });
    
      var form = document.getElementById("message_form");
      form.onsubmit = function(e) {
        var input = document.getElementById("message_input");
        var name  = document.getElementById("name_input"); 
    
        pubnub.publish({
          channel: 'chat',
          message: { name : name.value, text : input.value, userid :userid }
        });
        input.value = '';
        e.preventDefault();
      };
    </script>
    

    虽然此演示为您提供了一个快速简便的入门应用程序,但您还需要添加更多 enhanced chat security and chat authentication systems

    有关构建聊天应用程序的其他资源,请查看Build Real-time Chat Apps in 10 Lines of Code 指南和Building A Basic Chat Application

    聊天访问控制层 ACL

    您需要添加Security ACL Access Control Layer。使用 PubNub 访问管理器 (PAM),您可以通过授予用户访问令牌权限来控制谁具有访问权限。

    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    // Grant Chat Access to Secured Conversations
    // All server-side data is stored according to defined security policies.
    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    var pubnub = PUBNUB({ 
        publish_key:   "PUBLISH_KEY", 
        subscribe_key: "SUBSCRIBE_KEY", 
        secret_key:    "SECRET_KEY"
    })
    pubnub.grant({
        channel  : "CHANNEL",
        callback : receiver,
        error    : receiver,
        ttl      : 60, // Minutes
        read     : true,
        write    : true,
        auth_key : "AUTH_KEY"
    });
    

    建议在可信系统(例如您自己的数据中心服务器)上运行此级别的 ACL 代码。

    发送/接收安全加密消息

    PubNub 客户端库提供内置的高级加密标准 (AES) 256 位加密。要使用消息加密,只需在初始化时使用 cipher_key。

    使用 TLS 和 ssl 标志启用传输层加密。

    然后照常发布/订阅。

    var pubnub = PUBNUB({
        subscribe_key: 'sub-c-f762fb78-...',
        publish_key: 'pub-c-156a6d5f-...',
        ssl: true,
        cipher_key: 'my_cipherkey'
    });
    

    发件人身份验证邮件

    将用户信息附加到每条消息非常有效,并且在您的应用程序中提供了非常强大的灵活性。然而,恶意用户可能试图欺骗用户的身份并因此冒充其他用户。在示例应用程序中,我们展示了通过在 "message_form" 字段中更改您的姓名来轻松冒充任何人。这与您在使用电子邮件和 SMTP 时遇到的情况相同,除非您提供一种验证发件人身份的方法,否则可能会冒用任意电子邮件标头。有解决办法! ?

    数字签名是嵌入了消息有效负载关键组件的安全加密哈希的指纹,可选地包括盐(有时是时间戳),然后使用用于验证发送者身份的非对称密钥进行签名/加密。此过程用于阻止欺骗和冒充。

    A digital signature is a mathematical scheme for demonstrating the authenticity of a digital message or document.

    聊天应用的消息验证

    首先假设只有聊天用户被授予访问权限,他们可以使用 PubNub 访问管理器实现中提供的 grantrevoke 技术发布和订阅聊天频道。 这里的挑战是,在群聊室中,您的聊天用户已被授予auth_tokens,但他们仍然可以在频道上冒充其他聊天用户。

    这里的目标是在客户端收到消息时验证两件事。

    1. 发件人的身份。
    2. 消息的完整性。

    使用非对称加密,您可以通过创建数字签名为用户的消息提供一层验证和安全性。有效的数字签名使接收者有理由相信该消息是由已知的发件人创建的,发件人不能否认已发送该消息(身份验证和不可否认性),并且该消息在传输过程中未被更改(完整性)。数字签名通常用于金融交易和面向消息的通信,例如电子邮件和聊天,以及其他需要检测伪造或篡改的情况。

    您将首先在用户登录后通过您的服务器使用公钥(非对称)算法(例如 ECC/RSA)为每个聊天用户颁发一组密钥,服务器生成。我推荐 ECC,因为密钥大小比具有可比加密强度的 RSA 小得多。聊天室中的每个聊天用户都会通过安全的只读侧通道获知其他聊天用户的公钥。您的用户只能从由您的服务器的受信任和安全环境控制的公共只读通道接收公钥。您的服务器将能够将每个用户的公钥写入此只读通道。您的用户将从该频道阅读。

    在加入聊天室之前,您的用户可以通过 PubNub History 通话接收彼此的公钥。他们还应该打开对同一频道的订阅,以获取新聊天用户加入聊天室的公钥。

    用户的私钥不得暴露给经过验证的所有者以外的任何人。这可以在电子邮件/密码登录时完成,您可以在登录后立即将私钥发送给经过验证的用户。

    发送带有附加数字签名的聊天消息

    { userId: 123456,
    profilePic: "http://www.chats.com/user1234.jpg",
    message: "Hello World",
    signature: "tnnArxj06cWHq44gCs1OSKk/jLY" }
    

    您将通过连接以下基本字符串 (userId+profilePic+message) 来创建签名。接下来,您需要使用SHA1(signature_base_string)SHA256(signature_base_string) 计算消息摘要。现在,您可以使用此加密生成的哈希,使用 ECC/RSA 非对称算法使用用户的私钥进行签名。

    现在将此数字签名附加到聊天消息中,如上例所示,然后附加到聊天室消息验证的最后阶段。

    聊天室消息验证

    订阅聊天室频道后,您将收到用户发送的带有数字签名的聊天消息。您将使用此签名来验证聊天消息的真实性。如果该消息是企图欺骗,您将完全放弃该消息。

    // Digitally Signed Chat Message
    { userId: 123456,
    profilePic: "http://www.chats.com/user1234.jpg",
    message: "Hello World",
    signature: "tnnArxj06cWHq44gCs1OSKk/jLY" }
    

    要验证签名,您将通过连接以下基本字符串 (userId+profilePic+message) 创建签名。接下来,您需要使用SHA1(signature_base_string)SHA256(signature_base_string) 计算消息摘要。现在使用您已经拥有的用户 ID 123456 的聊天用户公钥,您可以验证/解密数字签名以获取您刚刚生成的原始消息摘要,该摘要也是由发件人创建的。

    比较当前消息摘要和原始消息摘要。如果它们相同,则消息是真实的,并且您已通过数字签名使用 消息验证 成功验证了发件人的消息。如果摘要不匹配,则这是一条虚假消息,您可以忽略冒充者。

    使用 PubNub 创建 PKI 公钥基础架构

    您需要一种通过只读 PKI安全传输公钥的方法。 PubNub 为您提供了一种向您的聊天用户公开安全只读 PKI 列表的方法。需要注意的是,PKI 需要非对称密钥算法,如 ECC 或 RSA。此外,我们正在使用这些加密算法来创建数字签名,而不是加密数据。这意味着我们将能够通过使用公钥成功解密签名并验证加盐签名字符串匹配来识别和验证发件人。

    1. 公钥用作解密密钥验证密钥
    2. 私钥用作加密密钥签名密钥

    请务必注意,您应该只打印从公钥可信来源检索到的用户名,而不是从消息内容中检索到的用户名。消息内容仅用于签名和验证身份。如果身份发生更改,则必须通过 PKI 使用 PubNub 的广播机制和存储和回放进行安全授权中继。

    访问令牌、身份名称/照片和非对称密钥只能从您服务器上的受信任执行环境中生成,并通过 PubNub 的授权只读 PKI 数据通道进行中继。

    【讨论】:

    • 我不明白...是什么阻止了某人接收我的消息、复制我的用户 ID 以及发送带有我的姓名和用户 ID 的消息?
    • 您好,是的,您需要添加 Security ACL Access Control Layer,我更新了答案以添加 ACL 使用示例。建议在可信系统(例如您自己的数据中心服务器)上运行此级别的 ACL 代码。
    • 我看不出 ACL 如何解决这个问题。当几个人发布时会出现问题,所以当然,ACL 应该允许他们发布。问题还是一样:谁在频道上发送了这条消息?是访问者A 还是访问者B?他们都被允许发布,但是是哪一个?
    • 好问题! -- 确保在消息负载中附加用户信息。 { name : my_name, profile : my_picture, text : my_message, userid : my_id }。另请查看此示例应用程序Creating a Polymer Chat App with Material Design
    • 你拔出了大炮,但至少,它可以工作,虽然正确签名的消息仍然可以重复,但这很容易解决。谢谢你的回答。
    【解决方案2】:

    在最新的 PubNub SDK (v4) 中,发布者 UUID 现在包含在订阅响应中。

    {
        actualChannel: null,
        channel: "my_channel_1",
        message: "Hello World!",
        publisher: "pn-58e1a647-3e8a-4c7f-bfa4-e007ea4b2073",
        subscribedChannel: "my_channel_1",
        subscription: null,
        timetoken: "14966804541029440"
    }
    

    【讨论】:

    • 历史呢?我找不到获取从历史 API 获取的消息的发布者 uuid 信息的方法
    • History 仅包含以 channel/publish timetoken 为 key 的已发布消息内容。如果您想保留该数据,请包含发布者的 UUID 和您以后可能想要使用的任何其他元数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 2011-12-11
    • 2020-05-10
    • 2015-07-06
    • 2017-08-28
    • 1970-01-01
    相关资源
    最近更新 更多