Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

262
Visualizações
Shuffle Password String para limitar los caracteres consecutivos de la misma clase

Entonces, trabajando en TI, tenemos el requisito de generar contraseñas seguras casi todo el tiempo, bueno, ciertas organizaciones agregan requisitos más estrictos más allá de la cantidad de clases de caracteres requeridas y los requisitos de longitud. Una de esas organizaciones para las que trabajo también limita la cantidad de caracteres de una sola clase de caracteres (minúsculas, mayúsculas, caracteres especiales, números) que pueden aparecer consecutivamente. He creado una función que facilita esto, sin embargo, esencialmente solo fuerza bruta la contraseña, lo cual es bastante terrible. ¿Cómo abordaría este problema en particular desde una perspectiva informática sabiendo que la velocidad es crítica mientras se mantiene la aleatoriedad?

Siento que debería haber algún tipo de técnica de reproducción aleatoria que pueda implementar, pero cada solución que se me ocurre es demasiado lenta o reduce la aleatoriedad de la cadena.

 Function New-Password { PARAM( [Int]$PasswordLength = 64, [Int]$MinUpperCase = 5, [Int]$MinLowerCase = 5, [Int]$MinSpecialCharacters = 5, [Int]$MinNumbers = 5, [Int]$ConsecutiveCharClass = 0, [Int]$ConsecutiveCharCheckCount = 1000, [String]$LowerCase = 'abcdefghiklmnoprstuvwxyz', [String]$UpperCase = 'ABCDEFGHKLMNOPRSTUVWXYZ', [String]$Numbers = '1234567890', [String]$SpecialCharacters = '!"$%&/()=?}][{@#*+', [String]$PasswordProfile = '', #Advanced Options [Bool]$EnhancedEntrophy = $True ) If ([String]::IsNullOrEmpty($PasswordProfile) -eq $False) { #You can define custom password profiles here for easy reference later on. New-Variable -Force -Name:'PasswordProfiles' -Value:@{ 'iDrac' = [PSCustomObject]@{PasswordLength=20;SpecialCharacters="+&?>-}|.!(',_[`"@#)*;$]/§%=<:{@";} } If ($PasswordProfile -in $PasswordProfiles.Keys) { $PasswordProfiles[$PasswordProfile] |Get-Member -MemberType NoteProperty |ForEach-Object { Set-Variable -Name $_.name -Value $PasswordProfiles[$PasswordProfile].($_.name) } } } New-Variable -Force -Name:'PassBldr' -Value @{} New-Variable -Force -Name:'CharacterClass' -Value:([String]::Empty) ForEach ($CharacterClass in @("UpperCase","LowerCase","SpecialCharacters","Numbers")) { $Characters = (Get-Variable -Name:$CharacterClass -ValueOnly) If ($Characters.Length -gt 0) { $PassBldr[$CharacterClass] = [PSCustomObject]@{ Min = (Get-Variable -Name:"min$CharacterClass" -ValueOnly); Characters = $Characters Length = $Characters.length } } } #Sanity Check(s) $MinimumChars = $MinUpperCase + $MinLowerCase + $MinSpecialCharacters + $MinNumbers If ($MinimumChars -gt $PasswordLength) { Write-Error -Message:"Specified number of minimum characters ($MinimumChars) is greater than password length ($PasswordLength)." Return } #New-Variable -Force -Name:'Random' -Value:(New-Object -TypeName:'System.Random') New-Variable -Force -Name:'Randomizer' -Value:$Null New-Variable -Force -Name:'Random' -Value:([ScriptBlock]::Create({ Param([Int]$Max=[Int32]::MaxValue,[Int32]$Min=1) if ($Min -gt $Max) { Write-Warning "[$($myinvocation.ScriptLineNumber)] Min ($Min) must be less than Max ($Max)." return -1 } if ($EnhancedEntrophy) { if ($Randomizer -eq $Null) { Set-Variable -Name:'Randomizer' -Value:(New-Object -TypeName:'System.Security.Cryptography.RNGCryptoServiceProvider') -Scope:1 } #initialize everything $Difference=$Max-$Min [Byte[]] $bytes = 1..4 #4 byte array for int32/uint32 #generate the number $Randomizer.getbytes($bytes) $Number = [System.BitConverter]::ToUInt32(($bytes),0) return ([Int32]($Number % $Difference + $Min)) } Else { if ($Randomizer -eq $Null) { Set-Variable -Name:'Randomizer' -Value:(New-Object -TypeName:'System.Random') -Scope:1 } return ([Int]$Randomizer.Next($Min,$Max)) } })) $GetString = [ScriptBlock]::Create({ Param([Int]$Length,[String]$Characters) Return ([String]$Characters[(1..$Length |ForEach-Object {& $Random $Characters.length})] -replace " ","") }) $CreatePassword = [scriptblock]::Create({ New-Variable -Name Password -Value ([System.Text.StringBuilder]::new()) -Force #Meet the minimum requirements for each character class ForEach ($CharacterClass in $PassBldr.Values) { If ($CharacterClass.Min -gt 0) { $Null = $Password.Append([string](Invoke-Command $GetString -ArgumentList $CharacterClass.Min,$CharacterClass.Characters)) } } #Now meet the minimum length requirements. If ([Int]($PasswordLength-$Password.length) -gt 0) { $Null = $Password.Append((Invoke-Command $GetString -ArgumentList ($PasswordLength-$Password.length),($PassBldr.Values.Characters -join ""))) } return (([Char[]]$Password.ToString() | Get-Random -Count $Password.Length) -join "") }) Switch ([Int]$ConsecutiveCharClass) { '0' { New-Variable -Name NewPassword -Value (& $CreatePassword) -Force } {$_ -gt 0} { New-Variable -Name CheckPass -Value $False -Force New-Variable -Name CheckCount -Value ([Int]0) -Force For ($I=0; $I -le $ConsecutiveCharCheckCount -and $CheckPass -eq $False; $I++) { New-Variable -Name NewPassword -Value (& $CreatePassword) -Force $TestPassed = 0 ForEach ($CharClass in $PassBldr.Values) { IF ([Regex]::IsMatch([Regex]::Escape($NewPassword),"[$([Regex]::Escape($CharClass.Characters))]{$ConsecutiveCharClass}") -eq $False) { $TestPassed++ } } if ($TestPassed -eq $CheckClasses.Count) { $CheckPass = $True } } } Default {Write-Warning -Message "This shouldn't be possible, how did you get here?!"} } Return $NewPassword }
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

¿Cómo abordaría este problema en particular desde una perspectiva informática sabiendo que la velocidad es crítica mientras se mantiene la aleatoriedad?

Antes de continuar, debo señalar que estas propiedades (cumplimiento de la política descrita versus mantenimiento de la aleatoriedad/entropía) son mutuamente excluyentes: no se puede "mantener la aleatoriedad" al "corregir" cuidadosamente la distribución de la salida de un PRNG.

Yo dividiría el problema en dos funciones separadas:

  • Test-PasswordCharSequence : para validar rápidamente si una cadena de contraseña dada cumple con la política
  • Shuffle-PasswordCharSequence : para mezclar aleatoriamente los caracteres en cualquier contraseña una vez

La atomización de estas operaciones centrales debería facilitar el ajuste/refactorización.

Para la función de validación, podría ser tentador usar una expresión regular, pero sugeriría simplemente iterar sobre la cadena y realizar un seguimiento de los caracteres consecutivos de la misma clase.

 function Test-PasswordCharSequence { param( [string] $String, [System.Collections.IDictionary] $CharacterMap, [int]$Limit = 5 ) # Keep tracking the last seen character class and length of consecutive sequence $currentClass = "" $counter = 0 foreach($char in $String.ToCharArray()) { if($CharacterMap.ContainsKey($char) -and $CharacterMap[$char] -eq $currentClass) { $counter++ } else { $counter = 1 $currentClass = $CharacterMap[$char] } # if we've seen the same class for too many consecutive characters, fail if($counter -gt $Limit){ return $false } } # No sequence over limit observed return $true }

Entonces necesitamos una función para mezclar la contraseña. El algoritmo de barajado verdaderamente aleatorio (nuevamente, dependiendo del RNG utilizado) más eficiente que conozco es el algoritmo de barajado in situ de Fisher-Yates , que se puede implementar de la siguiente manera:

 function Shuffle-PasswordCharSequence { param( [Parameter(Mandatory)] [string]$String ) $chars = $String.ToCharArray() $max = $chars.Length #Fisher-Yates Left to Right for($i = 0; $i -lt $max - 1; $i++) { $j = Get-Random -Minimum 0 -Maximum ($max - $i) $chars[$j],$chars[$i+$j] = $chars[$i+$j],$chars[$j] } return [string]::new($chars) }

Para usarlos junto con su función New-Password existente:

 # define character classes to use $CharacterClasses = @{ LowerCase = 'abcdefghiklmnoprstuvwxyz' UpperCase = 'ABCDEFGHKLMNOPRSTUVWXYZ' Numbers = '1234567890' SpecialCharacters = '!"$%&/()=?}][{@#*+' } # generate inverse character map for the validation function # we use [Dictionary[char,string]] rather than [hashtable] to ensure case-sensitive handling of keys ('b' vs 'B') $classMap = [System.Collections.Generic.Dictionary[char,string]]::new() foreach($entry in $CharacterClasses.GetEnumerator()) { foreach($char in $entry.Value.ToCharArray()) { $classMap[$char] = $entry.Name } } # generate initial password $passwordCandidate = New-Password -PasswordLength 127 @CharacterClasses # validate generated password, shuffle until successful $shuffleCount = 0 while(!(Test-PasswordCharSequence $passwordCandidate -CharacterMap $classMap)){ $passwordCandidate = Shuffle-PasswordCharSequence $passwordCandidate $shuffleCount++ } Write-Host "Generated valid password after ${shuffleCount} shuffles"
over 4 years ago · Santiago Trujillo Relatório

0

Creo que lo que @vonPryz mencionó en su comentario " ¿Por qué no construir la contraseña carácter por carácter? " es realmente posible y probablemente la forma más rápida de hacerlo.
El punto es que debe crear la contraseña en 2 etapas, primero cree una lista de complejidad con los conjuntos de caracteres (en lugar de los caracteres finales) y luego, en la siguiente etapa, seleccione el carácter en cuestión para el conjunto de caracteres en esa posición. Si se alcanza el $MaxConsecutiveChar , elija un nuevo carácter del conjunto de caracteres en esa posición:

 Function New-Password { Param( [Int]$PasswordLength = 64, [Int]$MinUpperCase = 5, [Int]$MinLowerCase = 5, [Int]$MinSpecialCharacters = 5, [Int]$MinNumbers = 5, [Int]$MaxConsecutiveChar = 3, [String]$LowerCase = 'abcdefghiklmnoprstuvwxyz', [String]$UpperCase = 'ABCDEFGHKLMNOPRSTUVWXYZ', [String]$Numbers = '1234567890', [String]$SpecialCharacters = '!"$%&/()=?}][{@#*+' ) enum CharSet { LowerCase UpperCase SpecialCharacters Numbers } $CharSets = [system.collections.generic.dictionary[CharSet, Char[]]]::new() $MinSetChars = [system.collections.generic.dictionary[CharSet, Int]]::new() $MinimumChars = 0 [CharSet].GetEnumNames().ForEach{ $CharSets[$_] = (Get-Variable -ValueOnly -Name $_).ToCharArray() $MinChar = [Int](Get-Variable -ValueOnly -Name "Min$_") $MinSetChars[$_] = $MinChar $MinimumChars += $MinChar } If ($MinimumChars -gt $PasswordLength) { Throw "Specified number of minimum characters ($MinimumChars) is greater than password length ($PasswordLength)." } # Build a list of characters sets $SetList = for ($i = 0; $i -lt $PasswordLength; $i++) { $CharSets.Keys |Get-Random } # Insert the Min* required characters for the specific sets # Making sure that the position is not already taken by another Min* characterset $Used = [System.Collections.Generic.HashSet[int]]::New() $CharSets.Keys.ForEach{ for ($i = 0; $i -lt $MinSetChars[$_]) { $At = Get-Random $PasswordLength if (!$Used.Contains[$At]) { $SetList[$At] = $_ $Null = $Used.Add($At) $i++ } } } # Elect a character for each set $LastChar = $Null $ConsecutiveChars = 1 -Join $SetList.ForEach{ $Char = $CharSets[$_] |Get-Random # Check the consecutive characters (choose another when required) While ($ConsecutiveChars -ge $MaxConsecutiveChar -and $Char -eq $LastChar) { $Char = $CharSets[$_] |Get-Random } $ConsecutiveChars = if ($Char -eq $LastChar) { $ConsecutiveChars + 1 } else { 1 } $LastChar = $Char $Char } }

 New-Password X23@[X0C5%FL3Demyf5?5})f]5Kt#usC#m1+3?T(NOb4DmYsX8FA3pF46OUZeW3V

Para probar que -MaxConsecutiveChar funciona y es rápido y silencioso:

 $Params = @{ MaxConsecutiveChar = 1 LowerCase = 'ab' UpperCase = 'ab' Numbers = 'ab' SpecialCharacters = 'ab' } New-Password @Params babababababababababababababababababababababababababababababababa
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda