Skip to content

Instantly share code, notes, and snippets.

@componhead
Forked from joepie91/random.md
Created December 31, 2020 14:55
Show Gist options
  • Save componhead/5ebdf64118d8d57d9a2bfafff64b2054 to your computer and use it in GitHub Desktop.
Save componhead/5ebdf64118d8d57d9a2bfafff64b2054 to your computer and use it in GitHub Desktop.

Revisions

  1. @joepie91 joepie91 revised this gist Nov 15, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion random.md
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,7 @@ There exist roughly three types of "random":
    * __Unpredictable:__ Not *truly* random, but impossible for an attacker to predict. This is what you need for security-related code - it doesn't matter *how* the data is generated, as long as it can't be guessed.
    * __Irregular:__ This is what most people think of when they think of "random". An example is a game with a background of a star field, where each star is drawn in a "random" position on the screen. This isn't truly random, and it isn't even unpredictable - it just doesn't *look* like there's a pattern to it, visually.

    *Irregular* data is fast to generate, but utterly worthless for security purpose - even if it doesn't seem like there's a pattern, there is almost always a way for an attacker to predict what the values are going to be. The only realistic usecase for irregular data is things that are represented visually, such as game elements or randomly generated phrases on a joke site.
    *Irregular* data is fast to generate, but utterly worthless for security purposes - even if it doesn't seem like there's a pattern, there is almost always a way for an attacker to predict what the values are going to be. The only realistic usecase for irregular data is things that are represented visually, such as game elements or randomly generated phrases on a joke site.

    *Unpredictable* data is a bit slower to generate, but still fast enough for most cases, and it's sufficiently hard to guess that it will be attacker-resistant. Unpredictable data is provided by what's called a __CSPRNG__.

  2. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion random.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,7 @@ Not all random values are created equal - for security-related code, you need a
    A summary of this article, if you don't want to read the entire thing:

    * __Don't use `Math.random()`.__ There are *extremely* few cases where `Math.random()` is the right answer. Don't use it, unless you've read this *entire* article, and determined that it's necessary for your case.
    * __Don't use `crypto.getRandomBytes` directly.__ While it's a CSPRNG, it's easy to bias the result when 'transforming' it, such that the output becomes more predictable.
    * __If you want to generate random tokens or API keys:__ Use [`uuid`](https://www.npmjs.com/package/uuid), specifically the `uuid.v4()` method. Avoid `node-uuid` - it's not the same package, and doesn't produce reliably secure random values.
    * __If you want to generate random numbers in a range:__ Use [`random-number-csprng`](https://www.npmjs.com/package/random-number-csprng).

    @@ -30,7 +31,7 @@ Every random value that you need for security-related purposes (ie. anything whe

    ## Bias

    In Node.js, the most widely available CSPRNG is the `crypto.getRandomBytes` function, but *you shouldn't use this directly*, as it's easy to mess up and "bias" your random values - that is, making it more likely that a specific value or set of values is picked.
    In Node.js, the most widely available CSPRNG is the `crypto.randomBytes` function, but *you shouldn't use this directly*, as it's easy to mess up and "bias" your random values - that is, making it more likely that a specific value or set of values is picked.

    A common example of this mistake is using the `%` modulo operator when you have less than 256 possibilities (since a single byte has 256 possible values). Doing so actually makes lower values *more likely* to be picked than higher values.

  3. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions random.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,13 @@
    Not all random values are created equal - for security-related code, you need a *specific kind* of random value.

    A summary of this article, if you don't want to read the entire thing:

    * __Don't use `Math.random()`.__ There are *extremely* few cases where `Math.random()` is the right answer. Don't use it, unless you've read this *entire* article, and determined that it's necessary for your case.
    * __If you want to generate random tokens or API keys:__ Use [`uuid`](https://www.npmjs.com/package/uuid), specifically the `uuid.v4()` method. Avoid `node-uuid` - it's not the same package, and doesn't produce reliably secure random values.
    * __If you want to generate random numbers in a range:__ Use [`random-number-csprng`](https://www.npmjs.com/package/random-number-csprng).

    You should seriously consider reading the entire article, though - it's not *that* long :)

    ## Types of "random"

    There exist roughly three types of "random":
  4. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 6 additions and 1 deletion.
    7 changes: 6 additions & 1 deletion random.md
    Original file line number Diff line number Diff line change
    @@ -49,4 +49,9 @@ This kind of difference may *look* small, but it's an easy and effective way for

    ## So, how do I obtain random values securely?

    In Node.js, if you need individual random numbers in a certain range, use [`random-number-csprng`](https://www.npmjs.com/package/random-number-csprng). If you need API keys or tokens of some sort, use [`uuid`](https://www.npmjs.com/package/uuid) (*not* `node-uuid`!), specifically the `uuid.v4()` method. Both of these use a CSPRNG, and 'transform' the bytes in an unbiased (ie. secure) way.
    In Node.js:

    * __If you need individual random numbers in a certain range:__ use [`random-number-csprng`](https://www.npmjs.com/package/random-number-csprng).
    * __If you need API keys or tokens of some sort:__ use [`uuid`](https://www.npmjs.com/package/uuid) (*not* `node-uuid`!), specifically the `uuid.v4()` method.

    Both of these use a CSPRNG, and 'transform' the bytes in an unbiased (ie. secure) way.
  5. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion random.md
    Original file line number Diff line number Diff line change
    @@ -47,6 +47,6 @@ If you look at the above list of ranges you'll notice that while there are __7 p

    This kind of difference may *look* small, but it's an easy and effective way for an attacker to reduce the amount of guesses they need when bruteforcing something. And this is only *one* way in which you can make your random values insecure, despite them originally coming from a secure random source.

    ## Obtaining random numbers securely
    ## So, how do I obtain random values securely?

    In Node.js, if you need individual random numbers in a certain range, use [`random-number-csprng`](https://www.npmjs.com/package/random-number-csprng). If you need API keys or tokens of some sort, use [`uuid`](https://www.npmjs.com/package/uuid) (*not* `node-uuid`!), specifically the `uuid.v4()` method. Both of these use a CSPRNG, and 'transform' the bytes in an unbiased (ie. secure) way.
  6. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions random.md
    Original file line number Diff line number Diff line change
    @@ -22,9 +22,11 @@ Every random value that you need for security-related purposes (ie. anything whe

    ## Bias

    In Node.js, the most widely available CSPRNG is the `crypto.getRandomBytes` function, but *you shouldn't use this directly*, as it's easy to mess up and "bias" your random values - that is, making it more likely that a specific value or set of values is picked. A common example of this mistake is using the `%` modulo operator when you have less than 256 possibilities (since a single byte has 256 possible values). Doing so actually makes lower values *more likely* to be picked than higher values.
    In Node.js, the most widely available CSPRNG is the `crypto.getRandomBytes` function, but *you shouldn't use this directly*, as it's easy to mess up and "bias" your random values - that is, making it more likely that a specific value or set of values is picked.

    For example, let's say that you have 36 possible random values - 0-9 plus every lowercase letter in a-z. A naive implementation might look something like this:
    A common example of this mistake is using the `%` modulo operator when you have less than 256 possibilities (since a single byte has 256 possible values). Doing so actually makes lower values *more likely* to be picked than higher values.

    For example, let's say that you have 36 possible random values - `0-9` plus every lowercase letter in `a-z`. A naive implementation might look something like this:

    ```js
    let randomCharacter = randomByte % 36;
  7. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion random.md
    Original file line number Diff line number Diff line change
    @@ -43,7 +43,7 @@ __That code is broken and insecure.__ With the code above, you essentially creat

    If you look at the above list of ranges you'll notice that while there are __7 possible values__ for each `randomCharacter` between 4 and 35 (inclusive), there are __8 possible values__ for each `randomCharacter` between 0 and 3 (inclusive). This means that while there's a __2.64% chance__ of getting a value between 4 and 35 (inclusive), there's a __3.02% chance__ of getting a value between 0 and 3 (inclusive).

    This kind of difference may look small, but it's an easy way for an attacker to reduce the amount of guesses they need when bruteforcing something. And this is only *one* way in which you can make your random values insecure, despite them originally coming from a secure random source.
    This kind of difference may *look* small, but it's an easy and effective way for an attacker to reduce the amount of guesses they need when bruteforcing something. And this is only *one* way in which you can make your random values insecure, despite them originally coming from a secure random source.

    ## Obtaining random numbers securely

  8. @joepie91 joepie91 revised this gist Nov 13, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion random.md
    Original file line number Diff line number Diff line change
    @@ -41,7 +41,7 @@ __That code is broken and insecure.__ With the code above, you essentially creat
    * __216-251__ becomes 0-35.
    * __252-255__ becomes *0-3*.

    If you look at the above list of ranges you'll notice that while there are 7 possible values for each `randomCharacter` between 4 and 35 (inclusive), there are __8 possible values__ for each `randomCharacter` between 0 and 3 (inclusive). This means that while there's a 2.64% chance of getting a value between 4 and 35 (inclusive), there's a __3.02% chance__ of getting a value between 0 and 3 (inclusive).
    If you look at the above list of ranges you'll notice that while there are __7 possible values__ for each `randomCharacter` between 4 and 35 (inclusive), there are __8 possible values__ for each `randomCharacter` between 0 and 3 (inclusive). This means that while there's a __2.64% chance__ of getting a value between 4 and 35 (inclusive), there's a __3.02% chance__ of getting a value between 0 and 3 (inclusive).

    This kind of difference may look small, but it's an easy way for an attacker to reduce the amount of guesses they need when bruteforcing something. And this is only *one* way in which you can make your random values insecure, despite them originally coming from a secure random source.

  9. @joepie91 joepie91 created this gist Nov 13, 2016.
    50 changes: 50 additions & 0 deletions random.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,50 @@
    Not all random values are created equal - for security-related code, you need a *specific kind* of random value.

    ## Types of "random"

    There exist roughly three types of "random":

    * __Truly random:__ Exactly as the name describes. True randomness, to which no pattern or algorithm applies. It's debatable whether this really exists.
    * __Unpredictable:__ Not *truly* random, but impossible for an attacker to predict. This is what you need for security-related code - it doesn't matter *how* the data is generated, as long as it can't be guessed.
    * __Irregular:__ This is what most people think of when they think of "random". An example is a game with a background of a star field, where each star is drawn in a "random" position on the screen. This isn't truly random, and it isn't even unpredictable - it just doesn't *look* like there's a pattern to it, visually.

    *Irregular* data is fast to generate, but utterly worthless for security purpose - even if it doesn't seem like there's a pattern, there is almost always a way for an attacker to predict what the values are going to be. The only realistic usecase for irregular data is things that are represented visually, such as game elements or randomly generated phrases on a joke site.

    *Unpredictable* data is a bit slower to generate, but still fast enough for most cases, and it's sufficiently hard to guess that it will be attacker-resistant. Unpredictable data is provided by what's called a __CSPRNG__.

    ## Types of RNGs (Random Number Generators)

    * __CSPRNG:__ A *Cryptographically Secure Pseudo-Random Number Generator*. This is what produces *unpredictable* data that you need for security purposes.
    * __PRNG:__ A *Pseudo-Random Number Generator*. This is a broader category that includes CSPRNGs *and* generators that just return irregular values - in other words, you *cannot* rely on a PRNG to provide you with unpredictable values.
    * __RNG:__ A *Random Number Generator*. The meaning of this term depends on the context. Most people use it as an even *broader* category that includes PRNGs and *truly* random number generators.

    Every random value that you need for security-related purposes (ie. anything where there exists the possibility of an "attacker"), should be generated using a __CSPRNG__. This includes verification tokens, reset tokens, lottery numbers, API keys, generated passwords, encryption keys, and so on, and so on.

    ## Bias

    In Node.js, the most widely available CSPRNG is the `crypto.getRandomBytes` function, but *you shouldn't use this directly*, as it's easy to mess up and "bias" your random values - that is, making it more likely that a specific value or set of values is picked. A common example of this mistake is using the `%` modulo operator when you have less than 256 possibilities (since a single byte has 256 possible values). Doing so actually makes lower values *more likely* to be picked than higher values.

    For example, let's say that you have 36 possible random values - 0-9 plus every lowercase letter in a-z. A naive implementation might look something like this:

    ```js
    let randomCharacter = randomByte % 36;
    ```

    __That code is broken and insecure.__ With the code above, you essentially create the following ranges (all inclusive):

    * __0-35__ stays 0-35.
    * __36-71__ becomes 0-35.
    * __72-107__ becomes 0-35.
    * __108-143__ becomes 0-35.
    * __144-179__ becomes 0-35.
    * __180-215__ becomes 0-35.
    * __216-251__ becomes 0-35.
    * __252-255__ becomes *0-3*.

    If you look at the above list of ranges you'll notice that while there are 7 possible values for each `randomCharacter` between 4 and 35 (inclusive), there are __8 possible values__ for each `randomCharacter` between 0 and 3 (inclusive). This means that while there's a 2.64% chance of getting a value between 4 and 35 (inclusive), there's a __3.02% chance__ of getting a value between 0 and 3 (inclusive).

    This kind of difference may look small, but it's an easy way for an attacker to reduce the amount of guesses they need when bruteforcing something. And this is only *one* way in which you can make your random values insecure, despite them originally coming from a secure random source.

    ## Obtaining random numbers securely

    In Node.js, if you need individual random numbers in a certain range, use [`random-number-csprng`](https://www.npmjs.com/package/random-number-csprng). If you need API keys or tokens of some sort, use [`uuid`](https://www.npmjs.com/package/uuid) (*not* `node-uuid`!), specifically the `uuid.v4()` method. Both of these use a CSPRNG, and 'transform' the bytes in an unbiased (ie. secure) way.