cleanup: strip remaining comment noise
This commit is contained in:
@@ -1,120 +1,57 @@
|
||||
component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographically-strong-random-tokens-in-coldfusion.htm*/
|
||||
component
|
||||
output = false
|
||||
hint = "Генерирует случайные токены с помощью Java SecureRandom."
|
||||
{
|
||||
|
||||
/**
|
||||
* Инициализирует генератор токенов.
|
||||
*
|
||||
* @output false
|
||||
*/
|
||||
public any function init() {
|
||||
|
||||
// Реализация генератора, используемая для построения случайных токенов.
|
||||
// SHA1PRNG не является алгоритмом по умолчанию во всех реализациях JVM,
|
||||
// поэтому он задается явно для предсказуемого поведения.
|
||||
generator = createObject( "java", "java.security.SecureRandom" )
|
||||
.getInstance(
|
||||
javaCast( "string", "SHA1PRNG" ),
|
||||
javaCast( "string", "SUN" )
|
||||
)
|
||||
;
|
||||
|
||||
// После инициализации нужно сгенерировать случайный байт,
|
||||
// чтобы генератор сам засеялся через общий источник seed.
|
||||
// Это может блокироваться до накопления достаточной энтропии,
|
||||
// поэтому операция выполняется при инициализации, а не при первом использовании.
|
||||
generator.nextBytes( charsetDecode( " ", "utf-8" ) );
|
||||
|
||||
// Момент следующего пересева генератора.
|
||||
// Это снижает риск слишком долгой работы с одним и тем же seed.
|
||||
reseedAt = getNextReseedAt();
|
||||
|
||||
return( this );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Публичные методы.
|
||||
|
||||
|
||||
/**
|
||||
* Генерирует криптографически стойкий токен из заданного числа случайных байтов.
|
||||
* Байт-массив кодируется в форму, пригодную для использования в URL.
|
||||
*
|
||||
* @byteCount Количество случайных байтов для генерации токена.
|
||||
* @output false
|
||||
*/
|
||||
public string function nextToken( numeric byteCount = 32 ) {
|
||||
|
||||
// Проверяем, нужен ли пересев генератора.
|
||||
if ( now() >= reseedAt ) {
|
||||
|
||||
// Пересев выполняется под lock, чтобы уменьшить гонки между потоками.
|
||||
// Если lock не получен вовремя, поток продолжает работу с текущим состоянием генератора.
|
||||
lock
|
||||
name = "TokenGenerator.reseedCheck"
|
||||
type = "exclusive"
|
||||
timeout = 1
|
||||
throwOnTimeout = false
|
||||
{
|
||||
|
||||
// Повторная проверка внутри lock: другой поток мог уже обновить seed.
|
||||
if ( now() >= reseedAt ) {
|
||||
|
||||
reseedAt = getNextReseedAt();
|
||||
|
||||
// Новый seed добавляется к уже существующему внутреннему состоянию генератора.
|
||||
generator.setSeed( generator.generateSeed( javaCast( "int", 32 ) ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Создаем буфер байтов, в который будут записаны случайные значения.
|
||||
var byteBuffer = charsetDecode( repeatString( " ", byteCount ), "utf-8" );
|
||||
|
||||
generator.nextBytes( byteBuffer );
|
||||
|
||||
return( encodeBytes( byteBuffer ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Приватные методы.
|
||||
|
||||
|
||||
/**
|
||||
* Кодирует массив байтов в строку токена.
|
||||
*
|
||||
* @bytes Кодируемый массив байтов.
|
||||
* @output false
|
||||
*/
|
||||
private string function encodeBytes( required binary bytes ) {
|
||||
|
||||
var token = binaryEncode( bytes, "base64" ); // *** вот поэтому длина отличается от заявленной
|
||||
|
||||
// мы хотим убрать все спецсимволы, потому что мы используем токен в качестве псевдослучайного суффикса
|
||||
var token = binaryEncode( bytes, "base64" );
|
||||
token = replace( token, "+", "a", "all" );
|
||||
token = replace( token, "/", "b", "all" );
|
||||
token = replace( token, "=", "c", "all" );
|
||||
|
||||
return( token );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Вычисляет время следующего пересева генератора.
|
||||
*
|
||||
* @output false
|
||||
*/
|
||||
private date function getNextReseedAt() {
|
||||
|
||||
return( dateAdd( "h", 1, now() ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user