cleanup: remove reasoning comments and translate helper docs
This commit is contained in:
+26
-61
@@ -1,19 +1,18 @@
|
||||
component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographically-strong-random-tokens-in-coldfusion.htm*/
|
||||
output = false
|
||||
hint = "I generate random tokens using Java's SecureRandom class."
|
||||
hint = "Генерирует случайные токены с помощью Java SecureRandom."
|
||||
{
|
||||
|
||||
/**
|
||||
* I initialize the token generator.
|
||||
* Инициализирует генератор токенов.
|
||||
*
|
||||
* @output false
|
||||
*/
|
||||
public any function init() {
|
||||
|
||||
// I am the generator implementation used to generate the random token data.
|
||||
// --
|
||||
// NOTE: The SHA1PRNG is not the default in all implementations of the JVM. As
|
||||
// such, we're defining the algorithm explicitly to keep this code consistent.
|
||||
// Реализация генератора, используемая для построения случайных токенов.
|
||||
// SHA1PRNG не является алгоритмом по умолчанию во всех реализациях JVM,
|
||||
// поэтому он задается явно для предсказуемого поведения.
|
||||
generator = createObject( "java", "java.security.SecureRandom" )
|
||||
.getInstance(
|
||||
javaCast( "string", "SHA1PRNG" ),
|
||||
@@ -21,22 +20,14 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
||||
)
|
||||
;
|
||||
|
||||
// Now that we've initialized the random generator, we have to generate a random
|
||||
// byte of data. This will ensure that the random generator is self-seeded using
|
||||
// a shared seed generator.
|
||||
// --
|
||||
// CAUTION: Since the underlying seed generator reads from sources of entropy,
|
||||
// this may hang until enough entropy has been collected. This is another good
|
||||
// reason to do it during initialization time rather than at first-use time.
|
||||
// После инициализации нужно сгенерировать случайный байт,
|
||||
// чтобы генератор сам засеялся через общий источник seed.
|
||||
// Это может блокироваться до накопления достаточной энтропии,
|
||||
// поэтому операция выполняется при инициализации, а не при первом использовании.
|
||||
generator.nextBytes( charsetDecode( " ", "utf-8" ) );
|
||||
|
||||
// I hold the future date at which time the generator should be reseeded in order
|
||||
// to keep it unpredictable.
|
||||
// --
|
||||
// NOTE: This doesn't affect the randomness of the values. But, the thinking
|
||||
// is that the longer the generator is producing values using the same seed,
|
||||
// the more likely an attacker is to be able to determine the original seed by
|
||||
// passively observing generated values.
|
||||
// Момент следующего пересева генератора.
|
||||
// Это снижает риск слишком долгой работы с одним и тем же seed.
|
||||
reseedAt = getNextReseedAt();
|
||||
|
||||
return( this );
|
||||
@@ -44,34 +35,23 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// PUBLIC METHODS.
|
||||
// ---
|
||||
// Публичные методы.
|
||||
|
||||
|
||||
/**
|
||||
* I generate "cryptographically strong" random token strings that are based on the
|
||||
* given number of random bytes. The random bytes are subsequently encoded using a
|
||||
* base64url character-set so that they are URL-safe and can be used in a variety of
|
||||
* contexts. And, since base65url is a case-sensitive schema, the tokens will
|
||||
* naturally be case-sensitive.
|
||||
* Генерирует криптографически стойкий токен из заданного числа случайных байтов.
|
||||
* Байт-массив кодируется в форму, пригодную для использования в URL.
|
||||
*
|
||||
* @byteCount I am the number of random bytes used to generate the token.
|
||||
* @byteCount Количество случайных байтов для генерации токена.
|
||||
* @output false
|
||||
*/
|
||||
public string function nextToken( numeric byteCount = 32 ) {
|
||||
|
||||
// Check to see if the generator needs to be reseeded (using a double-check
|
||||
// locking approach to reduce the bottleneck).
|
||||
// Проверяем, нужен ли пересев генератора.
|
||||
if ( now() >= reseedAt ) {
|
||||
|
||||
// Synchronize the reseeding.
|
||||
// --
|
||||
// NOTE: From what I have read, I DON'T BELIEVE that .generateSeed() will
|
||||
// ever hang with the SHA1PRNG algorithm. However, it is unclear to me. As
|
||||
// such, I'm using [throwOnTimeout = false] so that parallel threads won't
|
||||
// error if the lock cannot be obtained in a timely manner and will just
|
||||
// fall through to using the generator with the pre-seeding state.
|
||||
// Пересев выполняется под lock, чтобы уменьшить гонки между потоками.
|
||||
// Если lock не получен вовремя, поток продолжает работу с текущим состоянием генератора.
|
||||
lock
|
||||
name = "TokenGenerator.reseedCheck"
|
||||
type = "exclusive"
|
||||
@@ -79,27 +59,21 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
||||
throwOnTimeout = false
|
||||
{
|
||||
|
||||
// Perform double-check - generator may have already been reseeded by
|
||||
// a parallel request.
|
||||
// Повторная проверка внутри lock: другой поток мог уже обновить seed.
|
||||
if ( now() >= reseedAt ) {
|
||||
|
||||
reseedAt = getNextReseedAt();
|
||||
|
||||
// NOTE: Once the generator was seeded internally, this re-seeding
|
||||
// will only ever "add to" the existing seed. As such, this is still
|
||||
// building on top of the original randomness and calling this, on
|
||||
// interval, this will never reduce randomness.
|
||||
// Новый seed добавляется к уже существующему внутреннему состоянию генератора.
|
||||
generator.setSeed( generator.generateSeed( javaCast( "int", 32 ) ) );
|
||||
|
||||
}
|
||||
|
||||
} // END: Lock.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Create the byte buffer into which the random bytes will be written. Since
|
||||
// there's no "correct" way to generate a byte array in ColdFusion, we can
|
||||
// generate a string of the desired length and then decode it into bytes.
|
||||
// Создаем буфер байтов, в который будут записаны случайные значения.
|
||||
var byteBuffer = charsetDecode( repeatString( " ", byteCount ), "utf-8" );
|
||||
|
||||
generator.nextBytes( byteBuffer );
|
||||
@@ -109,27 +83,18 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// PRIVATE METHODS.
|
||||
// ---
|
||||
// Приватные методы.
|
||||
|
||||
|
||||
/**
|
||||
* I encode the given byte array using the base64url character-set.
|
||||
* Кодирует массив байтов в строку токена.
|
||||
*
|
||||
* @bytes I am the byte array being encoded.
|
||||
* @bytes Кодируемый массив байтов.
|
||||
* @output false
|
||||
*/
|
||||
private string function encodeBytes( required binary bytes ) {
|
||||
|
||||
var token = binaryEncode( bytes, "base64" ); // *** вот поэтому длина отличается от заявленной
|
||||
|
||||
// Replace the characters that are not allowed in the base64url format. The
|
||||
// characters [+, /, =] are removed for URL-based base64 values because they
|
||||
// have significant meaning in the context of URL paths and query-strings.
|
||||
/*token = replace( token, "+", "-", "all" );
|
||||
token = replace( token, "/", "_", "all" );
|
||||
token = replace( token, "=", "", "all" ); */
|
||||
|
||||
// мы хотим убрать все спецсимволы, потому что мы используем токен в качестве псевдослучайного суффикса
|
||||
token = replace( token, "+", "a", "all" );
|
||||
@@ -142,7 +107,7 @@ component /*https://www.bennadel.com/blog/2976-trying-to-generate-cryptographica
|
||||
|
||||
|
||||
/**
|
||||
* I calculate the next date of reseeding.
|
||||
* Вычисляет время следующего пересева генератора.
|
||||
*
|
||||
* @output false
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user