random länge - Wie generiere ich eine zufällige Zeichenfolge in Ruby?




titel startseite (25)

Ich habe kürzlich so etwas gemacht, um aus 62 Zeichen eine zufällige Zeichenfolge von 8 Byte zu erzeugen. Die Zeichen waren 0-9, az, AZ. Ich hatte ein Array von ihnen, als wurde es achtmal geloopt und wählte einen zufälligen Wert aus dem Array. Dies war in einer Schienen App.

str = '' 8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }

Das Seltsame ist, dass ich eine gute Anzahl von Duplikaten bekommen habe. Nun sollte das zufällig passieren. 62 ^ 8 ist riesig, aber von 1200 oder so Codes in der Datenbank hatte ich eine gute Anzahl von Duplikaten. Ich bemerkte, dass sie an den Stundengrenzen voneinander vorkamen. Mit anderen Worten, ich könnte ein Duplikat bei 12:12:23 und 2:12:22 oder so sehen ... nicht sicher, ob die Zeit das Problem ist oder nicht.

Dieser Code war in der vorherigen Erstellung eines ActiveRecord-Objekts. Bevor der Datensatz erstellt wurde, würde dieser Code laufen und den 'eindeutigen' Code erzeugen. Einträge in der db wurden immer zuverlässig erzeugt, aber der Code (str in der obigen Zeile) wurde viel zu oft dupliziert.

Ich erstellte ein Skript, um 100000 Iterationen dieser oberen Zeile mit geringer Verzögerung zu durchlaufen, so dass es 3-4 Stunden dauern würde, in der Hoffnung, eine Art von Wiederholungsmuster auf Stundenbasis zu sehen, aber nichts sah. Ich habe keine Ahnung, warum das in meiner Rails-App passiert ist.

Ich erzeuge derzeit eine 8-stellige Pseudozufalls-Großbuchstaben-Zeichenfolge für "A" .. "Z":

value = ""; 8.times{value  << (65 + rand(25)).chr}

aber es sieht nicht sauber aus und kann nicht als Argument übergeben werden, da es sich nicht um eine einzelne Aussage handelt. Um eine gemischte Zeichenfolge "a" .. "z" plus "A" .. "Z" zu erhalten, änderte ich es zu:

value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}

aber es sieht aus wie Müll.

Hat jemand eine bessere Methode?



SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

Etwas von Devise


Hier ist ein einfacher Code für zufälliges Passwort mit length 8

rand_password=('0'..'z').to_a.shuffle.first(8).join

Hoffe es wird helfen.


Rubin 1.9+:

ALPHABET = ('a'..'z').to_a
#=> ["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"]

10.times.map { ALPHABET.sample }.join
#=> "stkbssowre"

# or

10.times.inject('') { |s| s + ALPHABET.sample }
#=> "fdgvacnxhc"

require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]

Ich kann mich nicht erinnern, wo ich das gefunden habe, aber es scheint mir der beste und der kleinste Prozess zu sein, der intensiv ist:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[rand(chars.size)] }
  password
end

Ich mag die Antwort von Radar am besten, soweit ich denke. Ich würde ein bisschen so zwicken:

CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
  s=''
  length.times{ s << CHARS[rand(CHARS.length)] }
  s
end


Hier ist ein einfacher Code für eine zufällige Zeichenfolge mit der Länge 8

 random_string = ('0'..'z').to_a.shuffle.first(8).join

Sie können es auch für ein zufälliges Passwort mit der Länge 8 verwenden

random_password = ('0'..'z').to_a.shuffle.first(8).join

ich hoffe, es wird helfen und erstaunlich.


Seit Ruby 2.5 wirklich einfach mit SecureRandom.alphanumeric :

len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"

Erzeugt zufällige Zeichenfolgen mit AZ, az und 0-9 und sollte daher in den meisten Anwendungsfällen anwendbar sein. Und sie werden zufällig erzeugt, was auch ein Vorteil sein könnte.

Edit: Ein Benchmark zum Vergleich mit der Lösung mit den meisten Upvotes:

require 'benchmark'
require 'securerandom'

len = 10
n = 100_000

Benchmark.bm(12) do |x|
  x.report('SecureRandom') { n.times { SecureRandom.alphanumeric(len) } }
  x.report('rand') do
    o = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten
    n.times { (0...len).map { o[rand(o.length)] }.join }
  end
end
                   user     system      total        real
SecureRandom   0.429442   0.002746   0.432188 (  0.432705)
rand           0.306650   0.000716   0.307366 (  0.307745)

Die rand Lösung benötigt also nur 3/4 der Zeit von SecureRandom . Es ist wichtig, ob Sie wirklich viele Strings generieren, aber wenn Sie nur gelegentlich eine zufällige Zeichenfolge erstellen, würde ich immer mit der sichereren Implementierung arbeiten (da es auch einfacher ist, aufzurufen und expliziter zu sein).


Gegeben:

chars = [*('a'..'z'),*('0'..'9')].flatten

Einzelner Ausdruck, kann als Argument übergeben werden, erlaubt doppelte Zeichen:

Array.new(len) { chars.sample }.join

Vorsicht: rand ist für einen Angreifer vorhersehbar und daher wahrscheinlich unsicher. Sie sollten definitiv SecureRandom verwenden, wenn dies zum Generieren von Passwörtern dient. Ich benutze so etwas:

length = 10
characters = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a

password = SecureRandom.random_bytes(length).each_char.map do |char|
  characters[(char.ord % characters.length)]
end.join

Andere haben etwas Ähnliches erwähnt, aber dies verwendet die URL-Safe-Funktion.

require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="

Das Ergebnis kann AZ, az, 0-9, "-" und "_" enthalten. "=" Wird auch verwendet, wenn das Auffüllen wahr ist.


Diese Lösung benötigt eine externe Abhängigkeit, scheint aber hübscher als eine andere.

  1. Installiere den Edelstein- faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"

Meine 2 Cent:

  def token(length=16)
    chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
    (0..length).map {chars.sample}.join
  end

Mit dieser Methode können Sie eine beliebige Länge eingeben. Es ist standardmäßig auf 6 eingestellt.

def generate_random_string(length=6)
  string = ""
  chars = ("A".."Z").to_a
  length.times do
    string << chars[rand(chars.length-1)]
  end
  string
end

Array.new(n){[*"0".."9"].sample}.join , wobei in Ihrem Fall n = 8 ist.

Verallgemeinert: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join usw. - aus this Antwort


Ich denke, das ist ein gutes Gleichgewicht aus Prägnanz, Klarheit und einfacher Modifikation.

characters = ('a'..'z').to_a + ('A'..'Z').to_a
# Prior to 1.9, use .choice, not .sample
(0..8).map{characters.sample}.join

Leicht modifiziert

Zum Beispiel mit Ziffern:

characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a

Großbuchstaben hexadezimal:

characters = ('A'..'F').to_a + (0..9).to_a

Für eine wirklich beeindruckende Reihe von Charakteren:

characters = (32..126).to_a.pack('U*').chars.to_a

Wenn Sie eine Zeichenfolge mit der angegebenen Länge verwenden möchten, verwenden Sie Folgendes:

require 'securerandom'
randomstring = SecureRandom.hex(n)

Es erzeugt eine zufällige Zeichenfolge der Länge 2n mit 0-9 und af


Diese Lösung generiert eine Zeichenfolge mit leicht lesbaren Zeichen für Aktivierungscodes. Ich wollte nicht, dass Leute 8 mit B verwechseln, 1 mit I, 0 mit O, L mit 1 usw.

# Generates a random string from a set of easily readable characters
def generate_activation_code(size = 6)
  charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z}
  (0...size).map{ charset.to_a[rand(charset.size)] }.join
end

Eine andere Methode, die ich gerne benutze

 rand(2**256).to_s(36)[0..7]

Fügen Sie ljust wenn Sie wirklich paranoid sind über die richtige Länge der Zeichenfolge:

 rand(2**256).to_s(36).ljust(8,'a')[0..7]

(0...8).map { (65 + rand(26)).chr }.join

Ich verbringe zu viel Zeit Golf.

(0...50).map { ('a'..'z').to_a[rand(26)] }.join

Und eine letzte, die noch verwirrender, aber flexibler ist und weniger Zyklen verschwendet:

o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join


Einige Leute glauben, dass Sie den Speicher für das Speichern des Passworts überschreiben müssen, wenn Sie es nicht mehr benötigen. Dies reduziert das Zeitfenster, in dem ein Angreifer das Kennwort von Ihrem System lesen muss, und ignoriert vollständig die Tatsache, dass der Angreifer bereits ausreichend Zugriff auf den JVM-Speicher benötigt, um dies zu tun. Ein Angreifer mit so viel Zugriff kann Ihre Schlüsselereignisse abfangen, was diese völlig unbrauchbar macht (AFAIK, bitte korrigieren Sie mich, falls ich falsch liege).

Aktualisieren

Dank der Kommentare muss ich meine Antwort aktualisieren. Offensichtlich gibt es zwei Fälle, in denen dies zu einer (sehr) geringfügigen Sicherheitsverbesserung führen kann, da dadurch die Zeit verkürzt wird, die ein Kennwort auf der Festplatte landen kann. Dennoch denke ich, dass es für die meisten Anwendungsfälle zu viel ist.

  • Ihr Zielsystem ist möglicherweise nicht richtig konfiguriert oder Sie müssen davon ausgehen, dass dies der Fall ist und Sie müssen über Kernspeicherauszüge paranoid sein (kann gültig sein, wenn die Systeme nicht von einem Administrator verwaltet werden).
  • Ihre Software muss übermäßig paranoid sein, um Datenlecks zu vermeiden, bei denen der Angreifer Zugriff auf die Hardware erhält - beispielsweise mit TrueCrypt (nicht mehr CipherShed ), VeraCrypt oder CipherShed .

Wenn möglich, würde das Deaktivieren von Core-Dumps und der Auslagerungsdatei beide Probleme lösen. Sie würden jedoch Administratorrechte erfordern und möglicherweise die Funktionalität einschränken (weniger Arbeitsspeicher). Das Herausnehmen des Arbeitsspeichers von einem laufenden System wäre nach wie vor ein Problem.





ruby random passwords