【问题标题】:How to mask number to look as it would be random value如何屏蔽数字以使其看起来像随机值
【发布时间】:2013-07-02 17:40:41
【问题描述】:

可以从我当前正在处理的网页访问的数据库资源具有唯一的 ID 号,并设置了 auto_increment。所以 url 必须看起来像 some.web.page.com/resource/id-number

用户很容易注意到他可以在最后简单地增加或减少数字以获得他喜欢的任何东西,虽然在这种情况下安全性不是大问题,但我真的很想防止这种行为.

我试图找到一些可以将数字转换为类似随机字符串的函数,但我失败了(我真的不知道在 google.com 上的那个字段中输入什么;))。我也有自己的想法,但我更喜欢使用在某个地方已经行之有效的方法。该函数需要对称,以便我可以轻松生成字符串,并从该字符串中获取数字。有什么建议吗?

【问题讨论】:

    标签: numbers mask


    【解决方案1】:

    Ray Morgan 给出了 PHP 的算法和实现。该算法有几个不错的特性,即:

    • 该算法是确定性的,即总是为给定的数字 ID 值生成相同的模糊字符串。
    • 混淆是完全可逆的,即,如果您(仅)知道混淆的值,则可以提取基础数字 ID
    • 不会产生任何可识别的模式(例如简单的整数递增序列)
    • 它可以检测混淆的 ID 字符串是否被篡改

    作者自己解释基本步骤如下

    • 根据 $id 的哈希创建一个随机数 ($segment1)。
    • 根据 $segment1 的散列创建第二个随机数 ($segment2)。
    • 通过增加或减少$id 的值来改变$segment2。
    • 从 $segment1 和更改后的 $segment2 中创建第三个哈希 ($segment3)。该哈希值可以检测编码 ID 的任何更改。
    • 将三个段连接成一个字符串,
    • 瞧——你有你的混淆 ID。

    对于像我这样不熟悉 PHP 的人来说,该算法的工作 Common Lisp 端口可能如下所示:

    #-(and) (ql:quickload "ironclad")
    #-(and) (ql:quickload "trivial-utf-8")
    
    (defpackage "HASHID"
      (:use "COMMON-LISP" "IRONCLAD" "TRIVIAL-UTF-8")
      (:shadowing-import-from "COMMON-LISP" "NULL"))
    
    (in-package "HASHID")
    
    (defparameter +secret+ "Secret Password")
    
    (defun sha1-hex-digest (string &optional (secret +secret+))
      (let ((digest (make-digest :sha1)))
        (update-digest digest (string-to-utf-8-bytes string))
        (update-digest digest (string-to-utf-8-bytes secret))
        (let* ((result (produce-digest digest))
               (length (length result))
               (char-length (* length 2))
               (buffer (make-array char-length :element-type 'character))
               (digits "0123456789ABCDEF"))
          (loop
             :with wp := 0
             :for byte :across result
             :do (setf (char buffer (prog1 wp (incf wp))) (char digits (ash byte -4)))
                 (setf (char buffer (prog1 wp (incf wp))) (char digits (logand byte 15)))
             :finally (return buffer)))))
    
    
    (defun obfuscate-id (identifier)
      (let* ((segment-1 (subseq (sha1-hex-digest (format nil "~D" identifier)) 0 16))
             (segment-2 (subseq (sha1-hex-digest (concatenate 'string segment-1)) 0 8))
             (decimal (parse-integer segment-2 :radix 16))
             (buried-id (if (< identifier decimal) (- decimal identifier) (+ decimal identifier)))
             (new-segment-2 (format nil "~8,'0X" buried-id))
             (segment-3 (subseq (sha1-hex-digest (concatenate 'string segment-1 new-segment-2)) 0     8)))
        (concatenate 'string segment-1 new-segment-2 segment-3)))
    
    
    (defun deobfuscate-id (string)
      (let* ((segment-1 (subseq string 0 16))
             (segment-2 (subseq string 16 24))
             (segment-3 (subseq string 24))
             (expected-2 (subseq (sha1-hex-digest segment-1) 0 8))
             (expected-3 (subseq (sha1-hex-digest (concatenate 'string segment-1 segment-2)) 0 8)))
        (and (string-equal segment-3 expected-3)
             (let* ((v1 (parse-integer segment-2 :radix 16))
                    (v2 (parse-integer expected-2 :radix 16)))
               (abs (- v1 v2))))))
    

    请注意,最初的实现会根据经过混淆的 ID 生成 base-64 编码字符串,并将其用作实际值。我这里确实省略了这一步,但是添加起来应该很简单,特别是如果your programminglanguage of choicecomes withbase-64 support

    【讨论】:

    • 那,真的很好,谢谢 :)
    • 有没有机会在这个答案中写出(至少)那篇文章中使用的代码/实现/算法的简短描述?在 SO 上,只有链接答案通常不受欢迎。
    • @VijayRamamurthy - 一个人应该永远信守诺言。谢谢你打电话给我。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多