Как создать случайную строку, подходящую для идентификатора сеанса в PostgreSQL? - PullRequest
94 голосов
/ 19 октября 2010

Я хотел бы создать случайную строку для использования при верификации сеанса с использованием PostgreSQL.Я знаю, что могу получить случайное число с SELECT random(), поэтому я попробовал SELECT md5(random()), но это не работает.Как я могу это сделать?

Ответы [ 12 ]

210 голосов
/ 31 декабря 2010

Вы можете исправить свою первоначальную попытку следующим образом:

SELECT md5(random()::text);

Гораздо проще, чем некоторые другие предложения. : -)

68 голосов
/ 20 октября 2010

Я бы предложил это простое решение:

Это довольно простая функция, которая возвращает случайную строку заданной длины:

Create or replace function random_string(length integer) returns text as
$$
declare
  chars text[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}';
  result text := '';
  i integer := 0;
begin
  if length < 0 then
    raise exception 'Given length cannot be less than 0';
  end if;
  for i in 1..length loop
    result := result || chars[1+random()*(array_length(chars, 1)-1)];
  end loop;
  return result;
end;
$$ language plpgsql;

И использование:

select random_string(15);

Пример вывода:

select random_string(15) from generate_series(1,15);

  random_string
-----------------
 5emZKMYUB9C2vT6
 3i4JfnKraWduR0J
 R5xEfIZEllNynJR
 tMAxfql0iMWMIxM
 aPSYd7pDLcyibl2
 3fPDd54P5llb84Z
 VeywDb53oQfn9GZ
 BJGaXtfaIkN4NV8
 w1mvxzX33NTiBby
 knI1Opt4QDonHCJ
 P9KC5IBcLE0owBQ
 vvEEwc4qfV4VJLg
 ckpwwuG8YbMYQJi
 rFf6TchXTO3XsLs
 axdQvaLBitm6SDP
(15 rows)
28 голосов
/ 30 марта 2011

Опираясь на решение Марцина, вы можете использовать произвольный алфавит (в данном случае все 62 буквенно-цифровых символа ASCII):

SELECT array_to_string(array 
       ( 
              select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1)
              FROM   generate_series(1, 12)), '');
14 голосов
/ 12 января 2017

Вы можете получить 128 бит случайным образом из UUID.Это метод выполнения работы в современном PostgreSQL.

CREATE EXTENSION pgcrypto;
SELECT gen_random_uuid();

           gen_random_uuid            
--------------------------------------
 202ed325-b8b1-477f-8494-02475973a28f

Может быть тоже стоит прочитать документы по UUID

Тип данных uuidхранит универсальные уникальные идентификаторы (UUID) в соответствии с RFC 4122, ISO / IEC 9834-8: 2005 и соответствующими стандартами.(Некоторые системы называют этот тип данных глобально уникальным идентификатором, или GUID, вместо этого.) Этот идентификатор представляет собой 128-битное количество , которое генерируется алгоритмом, выбранным, чтобы сделать очень маловероятным, чтобы этот же идентификаторбудет генерироваться кем-либо еще в известной вселенной, используя тот же алгоритм.Следовательно, для распределенных систем эти идентификаторы обеспечивают лучшую гарантию уникальности, чем генераторы последовательностей, которые уникальны только в пределах одной базы данных.

Насколько редки конфликты с UUID или предположительные?Предполагая, что они случайные,

Необходимо будет сгенерировать около 100 триллионов UUID версии 4, чтобы иметь шанс 1 на миллиард одного дубликата («коллизия»).Вероятность одного столкновения возрастает до 50% только после генерирования 261 UUID (2,3 x 10 ^ 18 или 2,3 квинтиллиона).Соотнесение этих чисел с базами данных и рассмотрение вопроса о том, является ли вероятность коллизии UUID Версии 4 незначительной, рассмотрим файл, содержащий 2,3 квинтиллиона UUID Версии 4, с вероятностью 50%, содержащий одну коллизию UUID.Это будет 36 эксабайт по размеру, без учета других данных или издержек, в тысячи раз больше, чем самые большие базы данных, существующие в настоящее время, которые имеют порядок петабайт.При скорости генерирования 1 миллиарда UUID в секунду потребуется 73 года для генерации UUID для файла.Для его хранения также потребуется около 3,6 млн. 10-терабайтных жестких дисков или кассет с магнитной лентой, что не требует резервного копирования и резервирования.Чтение файла со стандартной скоростью передачи данных с диска в буфер 1 гигабит в секунду потребует более 3000 лет для одного процессора.Так как неисправимая частота ошибок чтения дисков составляет в лучшем случае 1 бит на 1018 бит, в то время как файл будет содержать около 1020 бит, простое чтение файла от начала до конца приведет, по крайней мере, к примерно 100-кратному увеличению количества ошибок.читать UUID, чем дубликаты.Ошибки хранения, сети, питания и других аппаратных и программных средств, несомненно, будут в тысячи раз чаще, чем проблемы с дублированием UUID.

source: wikipedia

InТаким образом,

  • UUID стандартизирован.
  • gen_random_uuid() - это 128 бит случайных чисел, сохраненных в 128 битах (2 ** 128 комбинаций).0-ненужный.
  • random() генерирует только 52 бита случайным образом в PostgreSQL (2 ** 52 комбинаций).
  • md5() хранится как UUID - 128 бит, но он может быть настолько случайным, как его входные данные ( 52 бит при использовании random())
  • md5(), сохраненные в виде текста, - 288 бит, но он может быть только случайнымв качестве входных данных ( 52 бит при использовании random()) - более чем в два раза больше размера UUID и доли случайности)
  • md5() в качестве хэша может быть оптимизированочто он мало что делает.
  • UUID очень эффективен для хранения: PostgreSQL предоставляет тип, который составляет ровно 128 бит.В отличие от text и varchar и т. Д., Которые хранятся в виде varlena с дополнительными издержками на длину строки.
  • Отличный UUID PostgreSQL поставляется с некоторыми операторами по умолчанию, приведениями и функциями.
13 голосов
/ 30 декабря 2010

Я недавно играл с PostgreSQL, и я думаю, что нашел немного лучшее решение, используя только встроенные методы PostgreSQL - без pl / pgsql.Единственным ограничением является то, что в настоящее время он генерирует только строки UPCASE, либо числа, либо строчные буквы.

template1=> SELECT array_to_string(ARRAY(SELECT chr((65 + round(random() * 25)) :: integer) FROM generate_series(1,12)), '');
 array_to_string
-----------------
 TFBEGODDVTDM

template1=> SELECT array_to_string(ARRAY(SELECT chr((48 + round(random() * 9)) :: integer) FROM generate_series(1,12)), '');
 array_to_string
-----------------
 868778103681

Второй аргумент метода generate_series определяет длину строки.

11 голосов
/ 22 марта 2013

Хотя по умолчанию он не активен, вы можете активировать одно из основных расширений:

CREATE EXTENSION IF NOT EXISTS pgcrypto;

Тогда ваш оператор становится простым вызовом gen_salt (), который генерирует случайную строку:

select gen_salt('md5') from generate_series(1,4);

 gen_salt
-----------
$1$M.QRlF4U
$1$cv7bNJDM
$1$av34779p
$1$ZQkrCXHD

Ведущий номер является хеш-идентификатором.Доступно несколько алгоритмов, каждый со своим собственным идентификатором:

  • md5: $ 1 $
  • bf: $ 2a $ 06 $
  • des: без идентификатора
  • xdes: _J9 ..

Дополнительная информация о расширениях:


РЕДАКТИРОВАТЬ

Как указано Эваном Кэролом, начиная с версии 9.4 вы можете использовать gen_random_uuid()

http://www.postgresql.org/docs/9.4/static/pgcrypto.html

10 голосов
/ 23 марта 2016

Пожалуйста, используйте string_agg!

SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '')
FROM   generate_series(1, 45);

Я использую это с MD5 также для генерации UUID. Я просто хочу случайное значение с большим количеством битов, чем целое число random ().

6 голосов
/ 13 февраля 2014

Я не думаю, что вы ищете случайную строку как таковую. Для проверки сеанса вам потребуется строка, которая гарантированно будет уникальной. Сохраняете ли вы информацию о проверке сеанса для аудита? В этом случае вам нужно, чтобы строка была уникальной между сессиями. Я знаю два, довольно простых подхода:

  1. Используйте последовательность. Подходит для использования в одной базе данных.
  2. Используйте UUID. Универсально уникален, так же хорош в распределенных средах.

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

Вам нужно загрузить расширение uuid-ossp, чтобы использовать UUID. После установки вызовите любую из доступных функций uuid_generate_vXXX () в вызовах SELECT, INSERT или UPDATE. Тип uuid - это 16-байтовая цифра, но он также имеет строковое представление.

4 голосов
/ 29 августа 2014

@ Кавиус рекомендует использовать pgcrypto, но вместо gen_salt, как насчет gen_random_bytes?А как насчет sha512 вместо md5?

create extension if not exists pgcrypto;
select digest(gen_random_bytes(1024), 'sha512');

Документы:

F.25.5.Функции случайных данных

gen_random_bytes (целое число отсчетов) возвращает байты

Возвращает количество криптографически стойких случайных байтов.Максимум 1024 байта могут быть извлечены за один раз.Это сделано для того, чтобы избежать опустошения пула генератора случайности.

4 голосов
/ 13 июля 2012

Параметр INTEGER определяет длину строки.Гарантировано, что все 62 буквенно-цифровых символа имеют одинаковую вероятность (в отличие от некоторых других решений, распространяющихся в Интернете).

CREATE OR REPLACE FUNCTION random_string(INTEGER)
RETURNS TEXT AS
$BODY$
SELECT array_to_string(
    ARRAY (
        SELECT substring(
            '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
            FROM (ceil(random()*62))::int FOR 1
        )
        FROM generate_series(1, $1)
    ), 
    ''
)
$BODY$
LANGUAGE sql VOLATILE;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...