Как замаскировать число, чтобы оно выглядело как случайное значение - PullRequest
2 голосов
/ 03 сентября 2011

Ресурсы базы данных, к которым можно получить доступ с веб-страницы, над которой я сейчас работаю, имеют уникальный идентификатор с установленным параметром auto_increment. Поэтому URL должен выглядеть примерно так: some.web.page.com/resource/id-number.

Для пользователя было бы легко заметить, что он может просто увеличивать или уменьшать число в конце, чтобы получить все, что ему нравится, и хотя в этом случае безопасность не является большой проблемой, я действительно хотел бы предотвратить такое поведение .

Я пытался найти какую-нибудь функцию, которая конвертировала бы число в случайную строку, похожую на похожую, но мне не удалось (я действительно не знал, что добавить в это поле на google.com;)). У меня тоже есть свои идеи, но я предпочитаю использовать метод, который уже где-то хорошо работает. Функция должна быть симметричной, чтобы я мог легко сгенерировать строку и получить число из этой строки. Любой совет?

1 Ответ

1 голос
/ 03 сентября 2011

Рэй Морган дает алгоритм и реализацию на PHP.Алгоритм имеет несколько приятных свойств, а именно:

  • алгоритм является детерминированным, т. Е. Всегда выдает одну и ту же запутанную строку для заданного числового значения идентификатора.
  • обфускация полностью обратимато есть, если вы знаете (только) запутанное значение, вы можете извлечь базовый числовой идентификатор
  • , который не дает никаких распознаваемых шаблонов (таких как простые возрастающие последовательности целых чисел)
  • можетопределить, был ли обфусцированный идентификатор строки подделан

Сам автор объясняет основные шаги следующим образом:

  • Создать случайное число ($ сегмент1) на основе хэша$ id.
  • Создайте второе случайное число ($ сегмент2) на основе хеша $ сегмент1.
  • Измените $ сегмент2, добавив или вычтя значение $ id.
  • Создайте третий хеш ($ сегмент3) из $ сегмент1 и измененный $ сегмент2.Этот хеш позволяет обнаружить любое изменение закодированного идентификатора.
  • Объединить три сегмента в строку,
  • и вуаля - у вас есть ваш запутанный идентификатор.

Для тех, кому не нравится 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))))))

Обратите внимание, что исходная реализация генерировала строку в кодировке base-64 из запутанного идентификатора ииспользовал это как фактическое значение.Я пропустил этот шаг здесь, но было бы просто добавить, в частности, если ваш язык программирования по выбору поставляется с base-64поддержка .

...