У меня есть файл CSV (значения, разделенные запятыми) Файл выглядит так:
20171108,120909470,SO1244,12,101
20171109,122715740,AG415757,11,101
Мне нужно скрыть данные в (например) столбцах 3 и, не затрагивая другие записи в файле.
Я хочу сделать это с помощью алгоритма хеширования, такого как SHA1 или MD5, чтобы одни и те же строки возвращались к одним и тем же значениям хеша везде, где они встречаются.
Мне нужно отправить данные третьей стороне, а некоторые столбцы содержат конфиденциальную информацию (например, имена клиентов). Мне нужно, чтобы файл был завершен, и когда строка заменяется, мне нужно, чтобы это выполнялось одинаково каждый раз, когда она встречается (чтобы оставалось любое сопоставление или группировка). Он не требует военного шифрования, просто чтобы его было трудно отменить. Поскольку мне нужно делать это с перерывами, идеальным решением было бы скриптовое решение.
Как проще всего добиться этого с помощью инструмента или сценария командной строки?
Я предпочитаю сценарий PowerShell, поскольку для этого не требуется никакого дополнительного программного обеспечения ...
Этот вопрос кажется дубликатом Мне нужно хешировать (скрыть) столбец данных в файле CSV. Предпочтительный сценарий, но предложенное решение не решило мою проблему и выдает следующую ошибку
You cannot call a method on a null-valued expression.
At C:\Users\mey\Hashr.ps1:4 char:5
+ $_.column3 = $_.column3.gethashcode()
Сценарий следующий
(Import-Csv .\results.csv -delimiter ',' ) | ForEach-Object{
$_.column3 = $_.column3.gethashcode()
$_
} | Export-Csv .\myobfuscated.csv -NoTypeInformation -delimiter ','
Обновлять:
Вот программа, которую я запускаю, и она была предложена @BaconBits:
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[String[]]
$String,
[Parameter(Position = 1)]
[ValidateSet('SHA1', 'MD5', 'SHA256', 'SHA384', 'SHA512')]
[String]
$HashName = 'SHA256'
)
process {
$StringBuilder = [System.Text.StringBuilder]::new(128)
[System.Security.Cryptography.HashAlgorithm]::Create($HashName).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ForEach-Object {
[Void]$StringBuilder.Append($_.ToString("x2"))
}
$StringBuilder.ToString()
}
}
$csv = Import-Csv .\results.csv -delimiter ','
foreach ($line in $csv) {
$line.column1 = Get-StringHash $line.column1
}
$csv | Export-Csv .\myobfuscated.csv -NoTypeInformation -delimiter ','
Файл csv, который я импортирую, является результатом другой созданной мной Java-программы, и он не создает заголовка, он просто заполняет файл csv значениями
Я получаю эту ошибку Get-StringHash: невозможно привязать аргумент к параметру String, поскольку он имеет значение NULL.
Основываясь на документ, вы не захотите использовать GetHashCode()
таким образом:
A hash code is intended for efficient insertion and lookup in collections that are based on a hash table. A hash code is not a permanent value. For this reason:
Do not serialize hash code values or store them in databases.
Do not use the hash code as the key to retrieve an object from a keyed collection.
Do not send hash codes across application domains or processes. In some cases, hash codes may be computed on a per-process or per-application domain basis.
Do not use the hash code instead of a value returned by a cryptographic hashing function if you need a cryptographically strong hash. For cryptographic hashes, use a class derived from the System.Security.Cryptography.HashAlgorithm or System.Security.Cryptography.KeyedHashAlgorithm class.
Do not test for equality of hash codes to determine whether two objects are equal. (Unequal objects can have identical hash codes.) To test for equality, call the ReferenceEquals or Equals method.
Пункт 4 - основная проблема. Нет гарантии, что хеширование необратимо. Используемая функция хеширования является деталью реализации, а не безопасной криптографической функцией, такой как SHA.
Я бы использовал такую функцию:
function Get-StringHash {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[String[]]
$String,
[Parameter(Position = 1)]
[ValidateSet('SHA1', 'MD5', 'SHA256', 'SHA384', 'SHA512')]
[String]
$HashName = 'SHA256'
)
process {
$StringBuilder = [System.Text.StringBuilder]::new(128)
[System.Security.Cryptography.HashAlgorithm]::Create($HashName).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ForEach-Object {
[Void]$StringBuilder.Append($_.ToString("x2"))
}
$StringBuilder.ToString()
}
}
$csv = Import-Csv .\results.csv -delimiter ',' -Header column1,column2,column3,column4,column5
foreach ($line in $csv) {
$line.column3 = Get-StringHash $line.column3
}
$csv | Export-Csv .\myobfuscated.csv -NoTypeInformation -delimiter ','
Я полагаю, что основал эту функцию на Вот этот, но прошло некоторое время с тех пор, как я ее написал.
Отредактируйте LotPings, чтобы показать результаты хеширования
"column1","column2","column3","column4","column5"
"20171108","120909470","0cdd3c3acdb7cfa107286565c044c5a0f1e58268f6f10e7e3415ff84942e577d","12","101 "
"20171109","122715740","0a7fb9f6bb7a180f2fd9429b0fbd1e7b0a83597b6a64aa6a123cef3e84700fe3","11","101"
@YacineWalid Похоже, вы ссылаетесь на несуществующий столбец. Вы уверены, что название вашей колонки - column3
? Что $csv[0]
показывает названия столбцов?
@YacineWalid Тогда я бы попробовал $line.'Column #2'
, если вам нужен третий столбец. Имя столбца, которое вы используете, должно совпадать с именами столбцов в заголовке CSV.
ДА, это работает, и сценарий работает правильно, но в файле csv результатов не происходит хеширования :(
Скрипт экспортирует в .\myobfuscated.csv
, а не в results.csv
, и здесь он работает.
да, конечно, он экспортируется в. \ myobfuscated.csv, но в моем случае хеширования не происходит
@LotPings, вы можете показать нам результат хеширования в вашем случае?
Я добавил содержимое файла myobfuscated.csv
в конце ответа @BaconBits.
Вот результат, который он показывает для меня '20171108, "120909470", "SO19086", "12", "101"' 20171108, "120918640", "SO455", "12", "101"
Он просто добавляет "" в каждый столбец, кроме первого.
@YacineWalid Похоже, мой код работает для меня и других. Вам нужно будет обновить вопрос, указав точный код, который вы используете, и хотя бы одну строку из вашего фактического файла данных включая заголовок. Вы не делаете того, чем занимаемся мы, и невозможно сказать, что именно.
@BaconBits Я обновил сообщение скриптом, который я запускаю, и csv, который я импортирую
@YacineWalid Вам нужно либо отредактировать csv, чтобы он содержал заголовки, либо добавить этот -Header column1,column2,column3,column4,column5
к команде Import-Csv
Большое спасибо за вашу помощь, я настоящий новичок в Powershell, и я вроде как борюсь с командами в данный момент, вы можете показать мне шаги для добавления '-header' к команде Import-Csv?
@YacineWalid см. Выше измененный сценарий. Кстати, вы должны отметить это как правильный ответ.
Bacon Bits, похоже, имеет правильную методологию за вычетом одной части. Цикл ForEach в исходном примере не изменяет исходную переменную. Кроме того, похоже, что столбец, который вы хотите изменить, - это не «Столбец 3», а «Столбец № 2», поскольку заголовки начинаются с нуля. Я повторю функцию, предоставленную в предложении Bacon Bits.
function Get-StringHash {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[String[]]
$String,
[Parameter(Position = 1)]
[ValidateSet('SHA1', 'MD5', 'SHA256', 'SHA384', 'SHA512')]
[String]
$HashName = 'SHA256'
)
process {
$StringBuilder = [System.Text.StringBuilder]::new(128)
[System.Security.Cryptography.HashAlgorithm]::Create($HashName).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) | ForEach-Object {
[Void]$StringBuilder.Append($_.ToString("x2"))
}
$StringBuilder.ToString()
}
}
Я бы предложил для замены:
$csv = Import-Csv .\results.csv | Select-Object *,@{n='Column #2';e = {Get-StringHash $_.'Column #2'}} -ExcludeProperty 'Column #2'
$CSV | Export-Csv .\myobfuscated.csv -NoTypeInformation
Это поместит "Столбец №2" последним в CSV. Вы можете просто перечислить их явно, если вам нужно, чтобы они отображались в том же порядке, например:
Select-Object 'Column #0','Column #1',@{n='Column #2';e = {Get-StringHash $_.'Column #2'}},'Column #3'
Это решение кажется точным, но и у меня оно не работает: // Select-Object: не найден параметр, который соответствует имени параметра ExcluedeProperty.
В своем сообщении вы неправильно написали "исключить". Если вы написали правильно, то, может быть, проблема в версии? Это определенно в версиях 3 и выше.
Большое спасибо за отзыв, но это вызывает еще одну ошибку. Get-StringHash: Невозможно привязать аргумент к параметру String, потому что он имеет значение null.