【问题标题】:How to encrypt a PIN that must be transmitted?如何加密必须传输的 PIN?
【发布时间】:2013-11-29 02:43:49
【问题描述】:

Dwolla 允许应用请求并存储用户的 PIN 作为预授权形式,但要求对其进行加密。来自TOS:

PIN 必须在传输和静止时加密(这包括任何和 所有备份介质)使用 FIPS 140-2 标准(至少)

通常,我会使用 Bcrypt 加密(实际上是进行安全哈希。Neil Slater,感谢您的纠正)(使用 bcrypt-ruby gem),例如密码。但是如果我使用 Bcrypt 加密,那么我必须传输哈希值,当然这与 Dwolla 的预期不符,并且 PIN 将被拒绝。

如何加密和解密 PIN 码以确保安全传输?

更新:

Andrew 链接到下面的问题中的一个答案引用了OpenSSL:Cipher,并且使用它我可以使用以下代码加密 PIN。但剩下的问题是:

  1. 我应该如何存储密钥、iv(初始化向量)和密码?保存为环境变量是否安全,或者将数据库表放入安全哈希中是否更好?
  2. 下面的代码作为一种加密 PIN 的方式有意义吗?
  3. 由于我没有来自 Dwolla 的公钥,那么传输它的最佳方式是什么?

pin = "1111" # this is what needs to be encrypted

#encryption:
cipher = OpenSSL::Cipher.new('AES-128-CBC') #=> #<OpenSSL::Cipher:0x00000100ef09d8>
cipher.encrypt
key = cipher.random_key #=> odd characters...
iv = cipher.random_iv #=> odd characters...
encrypted = cipher.update(pin) + cipher.final #=> odd characters...

#dcryption: 
decipher = OpenSSL::Cipher::AES.new(128, :CBC)
decipher.decrypt
decipher.key = key
decipher.iv = iv
plain = decipher.update(encrypted) + decipher.final

puts plain == pin #=> true

【问题讨论】:

    标签: ruby-on-rails ruby encryption ruby-on-rails-4 dwolla


    【解决方案1】:

    所以这就是我发现的。在 Rails 中,只生成一次密钥并将其存储为环境变量(并在部署时对其进行加密)。为每个引脚生成一个新的 iv(初始化向量)。将 iv 和加密的 pin 存储在数据库中。

    您可能希望将加密的 PIN 和 IV 转换为 UTF8,以便在不更改您设置数据库的方式的情况下成功保存。 (默认情况下,它们将生成为 ASCII 8 位)。

    这是在用户模型中执行此操作的一种方法,但您可能需要重构,因为这些方法很大:

    def dwolla_pin   # => this is to decrypt the PIN in order to use it
        unless encrypted_dwolla_pin.nil?
          decipher = OpenSSL::Cipher::AES.new(128, :CBC)
          decipher.decrypt
          decipher.key = ENV["ENCRYPT_KEY"]
    
          # Convert IV from UTF8 (as stored) back to ASCII-8bit (for OpenSSL)
          utf8_iv = self.iv_for_pin
          decipher.iv = Base64.decode64(utf8_iv.encode('ascii-8bit'))
    
          # Convert PIN from UTF8 (as stored) back to ASCII-8bit (for OpenSSL)
          utf8_pin = self.encrypted_dwolla_pin
          ascii_pin = Base64.decode64(utf8_pin.encode('ascii-8bit'))
    
          dwolla_pin ||= decipher.update(ascii_pin) + decipher.final
        end
      end
    
      def dwolla_pin=(new_pin)  # => this is to encrypt the PIN in order to store it
        return false unless valid_pin?(new_pin)
        cipher = OpenSSL::Cipher.new('AES-128-CBC')
        cipher.encrypt
        cipher.key = ENV["ENCRYPT_KEY"]
    
        # Create IV and convert to UTF-8 for storage in database
        iv = cipher.random_iv
        utf8_iv = Base64.encode64(iv).encode('utf-8')
        self.update_attribute(:iv_for_pin, utf8_iv)
    
        # Encrypt PIN and convert to UTF-8 for storage in database
        encrypted_pin = cipher.update(new_pin) + cipher.final
        utf8_pin = Base64.encode64(encrypted_pin).encode('utf-8')
        self.update_attribute(:encrypted_dwolla_pin, utf8_pin)
      end
    
      def valid_pin?(pin)  # => Here I'm just checking to make sure the PIN is basically in the right format
        pin.match(/^\d{4}/) && pin.length == 4
      end
    

    “安全传输”是指用于使用的 SSL 和用于部署的 SSH。如果部署到 Heroku,那么已经使用 SSH,但对于 SSL,您需要从 DNS 主机通配符证书和 Heroku 上的 ssl 端点购买。

    有人对此有什么要补充的吗?

    【讨论】:

      【解决方案2】:

      在这种情况下,我会使用公钥/私钥加密。不是 Ruby 方面的专家,但此链接可能会有所帮助:

      Ruby: file encryption/decryption with private/public keys

      如果您的 pin 被发送到外部,那么您需要最终用户的公钥进行加密。如果这不可能,那么您可以混合使用不对称(公共/私有)和对称算法 - 基本上就是 SSH 所做的。

      http://en.wikipedia.org/wiki/Secure_Shell

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-10
        • 2012-02-06
        • 2012-11-18
        • 1970-01-01
        • 2018-03-14
        • 2015-02-20
        • 2023-01-11
        相关资源
        最近更新 更多