Пред­ставь, что код — это тай­ник, но вмес­то золота там лежат твои пароли, клю­чи от сер­веров и про­чая кон­фиден­циаль­ная инфа. Но однажды ты слу­чай­но оста­вил его откры­тым, и теперь любой жела­ющий может заб­рать все, что захочет. Так себе пер­спек­тивка, вер­но? Поиск сек­ретов как раз то, что поможет най­ти и зак­рыть такие дыры. В сегод­няшней статье обсу­дим, как этот поиск авто­мати­зиро­вать.

По­иск сек­ретов (Secrets Detection) — это про­цесс обна­руже­ния и уда­ления так называ­емых чувс­тви­тель­ных дан­ных: паролей, клю­чей API, токенов дос­тупа, нас­тро­ек, которые могут слу­чай­но ока­зать­ся в исходном коде, кон­фигура­цион­ных фай­лах или дру­гих арте­фак­тах раз­работ­ки. Такие лазей­ки дают зло­умыш­ленни­ку лег­кий дос­туп к важ­ным сис­темам и сер­висам, что при­ведет к утеч­ке дан­ных или пол­ной ком­про­мета­ции.

Кста­ти, мно­гие отрасли тре­буют соб­людения стро­гих стан­дартов безопас­ности: GDPR, HIPAA, PCI DSS и дру­гих. Поиск и защита сек­ретов — одна из сос­тавля­ющих соот­ветс­твия этим стан­дартам.

Какие методы автоматизации выбрать?

Ис­кать сек­реты вруч­ную — все рав­но что про­сеивать песок в поис­ках кру­пицы золота. Поэто­му авто­мати­зация — единс­твен­ное надеж­ное решение. Искать сек­реты на потоке мож­но, нап­ример, с помощью регуляр­ных выраже­ний или путем ана­лиза энтро­пии. У каж­дого из под­ходов — свои плю­сы и минусы.

Регулярные выражения

Ре­гуляр­ные выраже­ния (regular expressions, regex, регуляр­ки) — это мощ­ный инс­тру­мент для манипу­ляций с тек­стом, исполь­зующий спе­циаль­ный син­таксис шаб­лонов, что­бы искать, менять и вытас­кивать дан­ные.

Сре­ди плю­сов:

  1. Точ­ность и воз­можность тон­кого кон­тро­ля. Мы можем задавать любые спе­цифи­чес­кие пат­терны для обна­руже­ния строк, что миними­зиру­ет количес­тво лож­ных сра­баты­ваний. Это осо­бен­но полез­но для поис­ка кон­крет­ных типов сек­ретов, таких как клю­чи API, пароли и токены дос­тупа.
  2. Гиб­кость. Пос­коль­ку регуляр­ные выраже­ния под­держи­вают слож­ные шаб­лоны, мы можем искать самую раз­ную инфу, вклю­чая email-адре­са, IP-адре­са, номера кре­дит­ных карт и любую дру­гую чувс­тви­тель­ную информа­цию.
  3. Прос­тота внед­рения. Мно­гие сре­ды раз­работ­ки и редак­торы кода име­ют встро­енную под­дер­жку regex, так­же есть биб­лиоте­ки поч­ти для любых язы­ков прог­рамми­рова­ния. Это поз­воля­ет лег­ко интегри­ровать регуляр­ки в любой про­ект.
  4. Ав­томати­зация. С исполь­зовани­ем сис­тем CI/CD regex мож­но нас­тро­ить для авто­мати­чес­кого ска­ниро­вания кода при каж­дом ком­мите, что помога­ет быс­тро обна­ружи­вать и устра­нять уяз­вимос­ти. Некото­рые инс­тру­мен­ты, нап­ример Gitleaks, поз­воля­ют исполь­зовать pre-commit hook, что повыша­ет уро­вень защиты от уте­чек.

Так в чем под­вох? Если все так прек­расно, то зачем вооб­ще исполь­зовать что‑то еще? Дело в том, что у это­го метода так­же есть и минусы.

  1. За­виси­мость от шаб­лонов. Регуляр­ки эффектив­ны толь­ко для поис­ка извес­тных шаб­лонов и могут про­пус­кать сек­реты, которые им не соот­ветс­тву­ют. Если фор­мат меня­ется или исполь­зует­ся уни­каль­ный, то инс­тру­мент на базе регуляр­ных выраже­ний может ничего не обна­ружить.
  2. Слож­ность соз­дания регуляр­ных выраже­ний и управле­ния ими. Написа­ние эффектив­ных и безопас­ных регуля­рок может быть неп­ростой задачей, осо­бен­но для нес­тандар­тных шаб­лонов.
  3. Лож­ные сра­баты­вания. Если шаб­лон слиш­ком общий, он обна­ружи­вает стро­ки, которые не явля­ются сек­ретами. Поэто­му филь­тро­вать и ана­лизи­ровать при­дет­ся допол­нитель­но и уже руч­ками.
  4. Про­изво­дитель­ность. Слож­ные регуляр­ные выраже­ния могут мед­ленно работать на боль­ших фай­лах или мно­жес­тве фай­лов.

Анализ энтропии

По­мимо регуляр­ных выраже­ний, при поис­ке сек­ретов при­меня­ют еще один эффектив­ный метод — ана­лиз энтро­пии. Для начала давай раз­берем основные тер­мины.

Эн­тро­пия — это показа­тель, который поз­воля­ет оце­нить сте­пень слу­чай­нос­ти или, наобо­рот, пред­ска­зуемос­ти дан­ных. В кон­тек­сте поис­ка сек­ретов в коде он помога­ет выделить фраг­менты, которые отли­чают­ся от осталь­ного тек­ста по сво­ей струк­туре и, воз­можно, содер­жат скры­тую информа­цию, такую как пароли, клю­чи или токены. Чем выше энтро­пия, тем более слу­чай­ная и неп­ред­ска­зуемая стро­ка.

Для рас­чета энтро­пии стро­ки есть матема­тичес­кая фор­мула Кло­да Шен­нона. Общий про­цесс вычис­ления энтро­пии выг­лядит так:

  1. Чте­ние стро­ки: сна­чала берет­ся стро­ка из кода или фай­ла, нап­ример a9$L2@xZ.
  2. Под­счет сим­волов: под­счи­тыва­ется количес­тво каж­дого сим­вола в стро­ке.
  3. Вы­чис­ление веро­ятности: опре­деля­ется, как час­то каж­дый сим­вол появ­ляет­ся в стро­ке. Нап­ример, a встре­чает­ся один раз из вось­ми сим­волов.
  4. Рас­чет энтро­пии.

где

Сек­реты, такие как пароли или клю­чи API, час­то име­ют высокую энтро­пию, потому что они соз­даны для безопас­ности и содер­жат мно­го слу­чай­ных сим­волов. Ана­лиз энтро­пии помога­ет обна­ружи­вать такие стро­ки в коде, пос­коль­ку обыч­ный текст (нап­ример, ком­мента­рии или обыч­ные перемен­ные) чаще все­го име­ет низ­кую энтро­пию.

Пос­ле вычис­ления энтро­пии уста­нав­лива­ется некий порог, выше которо­го все стро­ки счи­тают­ся потен­циаль­ными сек­ретами. Он зависит от кон­крет­ной сре­ды и типов дан­ных, но час­то выбира­ется эмпи­ричес­ки. Даль­ше надо филь­тро­вать и ана­лизи­ровать най­ден­ные стро­ки.

А теперь о пре­иму­щес­твах и недос­татках это­го метода. Пре­иму­щес­тва:

  1. Об­наруже­ние неиз­вес­тных шаб­лонов. Исполь­зование энтро­пии поз­воля­ет выяв­лять слу­чай­ные стро­ки, которые могут не соот­ветс­тво­вать извес­тным шаб­лонам сек­ретов.
  2. Ав­томати­чес­кое обновле­ние. Метод не тре­бует пос­тоян­ного обновле­ния пра­вил или шаб­лонов при изме­нении фор­мата сек­ретов.
  3. Ши­рокий охват. Мож­но выяв­лять раз­ные типы сек­ретов без соз­дания спе­цифи­чес­ких шаб­лонов.

Ана­лиз энтро­пии удоб­ный, но не иде­аль­ный метод. Вот какие у него есть минусы:

  1. Лож­ные сра­баты­вания. Увы, пока что не сущес­тву­ет ни одно­го метода без это­го косяка. Высокая энтро­пия может быть у строк, которые не явля­ются сек­ретами (нап­ример, хеши, слу­чай­ные дан­ные), что при­водит к лож­ным сра­баты­вани­ям.
  2. Слож­ность нас­трой­ки. Спо­соб тре­бует тща­тель­ной нас­трой­ки порогов энтро­пии, что­бы сба­лан­сировать точ­ность и количес­тво лож­ных сра­баты­ваний.
  3. Про­изво­дитель­ность. Ана­лиз энтро­пии может быть вычис­литель­но зат­ратным, осо­бен­но для боль­ших объ­емов дан­ных.

Как видишь, слож­ность нас­трой­ки и зат­рата ресур­сов — неиз­бежные минусы в любом слу­чае. Но детали могут отли­чать­ся в зависи­мос­ти от реали­зации того и дру­гого метода.

Какие есть инструменты?

По­иск сек­ретов — один из про­цес­сов раз­работ­ки безопас­ного прог­рам­мно­го обес­печения. По ГОСТ 56939 здесь мы так­же можем исполь­зовать инс­тру­мен­ты ста­тичес­кого ана­лиза. Одна­ко прак­тика показы­вает, что его качес­тво оставля­ет желать луч­шего. Поэто­му в рам­ках иссле­дова­ния рас­смот­рим три инс­тру­мен­та:

Gitleaks — это инс­тру­мент для обна­руже­ния сек­ретов пре­иму­щес­твен­но в репози­тори­ях Git, но при нор­маль­ной нас­трой­ке он так­же может ска­ниро­вать локаль­ные исходные дан­ные. Этот инс­тру­мент исполь­зует как регуляр­ные выраже­ния, так и ана­лиз энтро­пии для поис­ка кон­фиден­циаль­ной инфы, что дела­ет его неверо­ятно полез­ным для пре­дот­вра­щения уте­чек информа­ции.

Gitleaks под­держи­вает мно­жес­тво шаб­лонов для раз­ных сек­ретов, име­ет воз­можность гиб­кой нас­трой­ки — поль­зователь сам может редак­тировать пра­вила и шаб­лоны для более точ­ного обна­руже­ния. Gitleaks лег­ко интегри­рует­ся с пай­плай­нами CI/CD, обес­печивая авто­мати­чес­кое ска­ниро­вание на эта­пе раз­работ­ки. А еще он бес­плат­ный и у него активное сооб­щес­тво, что спо­собс­тву­ет его раз­витию и улуч­шению. Но здесь есть недос­таток: ана­лиз энтро­пии не всег­да может быть точ­ным и тре­бует тща­тель­ной нас­трой­ки порогов.

TruffleHog находит сек­реты в репози­тори­ях Git и дру­гих сис­темах кон­тро­ля вер­сий. Он при­меня­ет регуляр­ные выраже­ния для обна­руже­ния извес­тных типов сек­ретов, а до вер­сии 3 вклю­чал и ана­лиз энтро­пии. Нес­мотря на некото­рые огра­ниче­ния, такие как про­изво­дитель­ность и лож­ные сра­баты­вания, TruffleHog оста­ется популяр­ным выбором бла­года­ря прос­тоте исполь­зования.

Пос­ледний в нашем обзо­ре — Detect Secrets. Что­бы обна­ружить сек­ретную информа­цию, он исполь­зует ком­бинацию регуляр­ных выраже­ний, ана­лиза энтро­пии и спец­пла­гинов. Бла­года­ря сво­ей гиб­кости и воз­можнос­ти интегра­ции с CI/CD Detect Secrets поль­зует­ся популяр­ностью сре­ди раз­работ­чиков и спе­циалис­тов по безопас­ности. Но имей в виду: что­бы все работа­ло эффектив­но, при­дет­ся попотеть на эта­пе нас­трой­ки и филь­тра­ции лож­ных сра­баты­ваний.

Краткая характеристика базовых инструментов

Оцениваем эффективность инструментов на практике

У каж­дого из этих инс­тру­мен­тов свои тест‑кей­сы, но мы наш­ли кое‑что поин­терес­нее. Тес­тировать будем на OWASP WrongSecrets. Этот про­ект пре­дос­тавля­ет инте­рак­тивную плат­форму, где раз­работ­чики и спе­циалис­ты по безопас­ности могут учить­ся на прак­тике, как пра­виль­но хра­нить сек­реты, такие как API-клю­чи, пароли, токены дос­тупа и кон­фиден­циаль­ные дан­ные, и управлять ими. Он спе­циаль­но соз­дан для демонс­тра­ции неп­равиль­ного обра­щения с сек­ретами в при­ложе­ниях и для обу­чения луч­шим прак­тикам их защиты. Это дела­ет его иде­аль­ной тес­товой сре­дой инс­тру­мен­тов, пред­назна­чен­ных для поис­ка и управле­ния сек­ретами.

Пос­мотрим, что най­дут инс­тру­мен­ты, если мы не будем тро­гать нас­трой­ки по умол­чанию.

Gitleaks

Для запус­ка инс­тру­мен­та исполь­зовалась сле­дующая коман­да:

docker run -v /путь/до/wrongsecrets-master/:/path zricethezav/gitleaks:latest detect --no-git --source="/path" -r="/path/gitleaks_report.json"

Здесь пап­ка с исходни­ками локаль­ная, поэто­му исполь­зует­ся ключ --no-git. В резуль­тате ска­ниро­вания мы получи­ли файл gitleaks_report.json, содер­жащий 20 най­ден­ных сек­ретов. Из них 9 сек­ретов приз­наны лож­но положи­тель­ными.

Для чис­тоты экспе­римен­та запус­тим стан­дар­тное ска­ниро­вание, но с кон­фигура­цион­ным фай­лом, который пред­лага­ют раз­работ­чики Gitleaks:

docker run -v /исходная/директория:/path zricethezav/gitleaks:latest detect --no-git --config="/path/gitleaks.toml" --source="/path/wrongsecrets-master -r="/path/gitleaks_report.json""

И сно­ва получим 20 най­ден­ных сек­ретов, из которых 9 — лож­ные сра­баты­вания.

TruffleHog

Этот инс­тру­мент запус­кался сле­дующей коман­дой:

run --rm -it -v "$PWD:/pwd" trufflesecurity/trufflehog:latest filesystem /pwd/wrongsecrets-master/ > trufflehog_local_report.txt

По­лучен­ный файл trufflehog_local_report.txt не содер­жал ни одно­го най­ден­ного сек­рета! В свя­зи с этим приш­лось выпол­нить ряд манипу­ляций:

  1. Соз­дать кон­фигура­цион­ный файл trufflehog_config.toml для более обширно­го и точ­ного ана­лиза.
  2. Добавить клю­чи: --debug (вклю­чает режим отладки для получе­ния более под­робной информа­ции о про­цес­се ска­ниро­вания), --trace (вклю­чает более под­робный уро­вень отладки, который может помочь понять, что имен­но ска­ниру­ется и какие дей­ствия выпол­няют­ся), --json (вклю­чает вывод резуль­татов в фор­мате JSON, что удоб­но для пос­леду­юще­го ана­лиза).
  3. Изу­чить резуль­таты.

Пол­ная коман­да для запус­ка в этом слу­чае выг­лядела так:

docker run --rm -it -v "$PWD:/pwd" -v "$PWD/trufflehog_config.toml:/config/trufflehog_config.toml" trufflesecurity/trufflehog:latest filesystem /pwd/wrongsecrets-master/ --debug --trace --json

При этом уда­лось най­ти лишь один сек­рет. Ока­залось, что TruffleHog не может пра­виль­но обра­баты­вать некото­рые дан­ные и в ито­ге про­пус­кает важ­ные сек­реты. Так что он подой­дет для репози­тори­ев и тек­сто­вых фай­лов, но дан­ные дру­гих типов ска­ниро­вать им поч­ти бес­полез­но.

В общем, TruffleHog име­ет слиш­ком мно­го огра­ниче­ний, а зна­чит, выбыва­ет из нашей гон­ки.

Detect Secrets

За­пус­кает­ся инс­тру­мент сле­дующей коман­дой:

detect-secrets scan --all-files ./wrongsecrets-master/ > detect_sec.txt

По­лучен­ный файл detect_sec.txt содер­жал 66 сек­ретов. Из них под­твержде­ны 42.

Та­ким обра­зом, при при­мене­нии стан­дар­тных нас­тро­ек пред­став­ленных инс­тру­мен­тов луч­ше все­го себя показа­ли Detect Secrets и Gitleaks.

Те­перь запус­тим инс­тру­мен­ты на том же тес­товом при­мере, но пол­ностью отклю­чим ана­лиз энтро­пии.

Нач­нем с Detect Secrets. Его исполь­зуют для ана­лиза пла­гинов и филь­тров. Филь­тры при­меня­ются для умень­шения лож­ных сра­баты­ваний и отсе­ивают потен­циаль­ные сек­реты по опре­делен­ным кри­тери­ям, преж­де чем резуль­таты будут про­вере­ны пла­гина­ми. Пла­гины — это и есть основные нас­трой­ки, каж­дая из которых спе­циали­зиру­ется на поис­ке опре­делен­ного типа сек­ретов в фай­лах. Есть воз­можность написать собс­твен­ный филь­тр и под­клю­чить его к ска­ниро­ванию. Для прос­мотра спис­ка пла­гинов есть коман­да:

detect-secrets scan --list-all-plugins

В резуль­тате мы получим все исполь­зуемые в ска­ниро­вании пла­гины. Те, что отве­чают за ана­лиз энтро­пии, носят наз­вания Base64HighEntropyString и HexHighEntropyString. Их нам и надо отклю­чить для ана­лиза. Запус­тим ска­ниро­вание:

detect-secrets scan --all-files --disable-plugin Base64HighEntropyString --disable-plugin HexHighEntropyString ./wrongsecrets-master > ./detect_sec_no_entropy.txt

По­луча­ем файл, содер­жащий 42 сек­рета. Из которых толь­ко 23 — истинные. Таким обра­зом, мы вылови­ли куда мень­ше уте­чек, чем в пре­дыду­щем ска­ниро­вании.

Те­перь напишем regex-пра­вила в фор­мате TOML для Gitleaks. Пусть у нас будет такой базовый набор:

title = "Enhanced Gitleaks Configuration"
version = 2
[[rules]]
id = "AWS Access Key"
description = "AWS Access Key"
regex = '''AKIA[0-9A-Z]{16}'''
tags = ["key", "AWS"]
[[rules]]
id = "AWS Secret Key"
description = "AWS Secret Key"
regex = '''(?i)aws(.{0,20})?['"][0-9a-zA-Z\/+]{40}['"]'''
tags = ["key", "AWS"]
[[rules]]
id = "Google API Key"
description = "Google API Key"
regex = '''AIza[0-9A-Za-z-_]{35}'''
tags = ["key", "Google"]
[[rules]]
id = "Slack Token"
description = "Slack Token"
regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})'''
tags = ["token", "Slack"]
[[rules]]
id = "SSH Private Key"
description = "SSH Private Key"
regex = '''-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----'''
tags = ["key", "SSH"]
[[rules]]
id = "Generic API Key"
description = "Generic API Key"
regex = '''(?i)(apikey|api_key|secret_key|client_secret|access_token)[\s]*[=:][\s]*['"]?[A-Za-z0-9\/+=-_]{32,64}['"]?'''
tags = ["key", "API"]
[[rules]]
id = "Generic Secret"
description = "Generic Secret"
regex = '''(?i)(secret|password|pwd|token|key|auth)[\s]*[=:][\s]*['"]?[A-Za-z0-9\/+=-_]{8,128}['"]?'''
tags = ["secret"]
[[rules]]
id = "Database Connection String"
description = "Database Connection String"
regex = '''(?i)(mongodb|postgres|mysql|sqlserver|redis|couchdb|oracle):\/\/[^\s]+'''
tags = ["database", "connection"]
[[rules]]
id = "Google OAuth Client ID"
description = "Google OAuth Client ID"
regex = '''[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com'''
tags = ["oauth", "Google"]
[[rules]]
id = "Google OAuth Client Secret"
description = "Google OAuth Client Secret"
regex = '''(?i)("client_secret":\s*["'][A-Za-z0-9-_]{24}["'])'''
tags = ["oauth", "Google"]
[[rules]]
id = "Private Key"
description = "Private Key"
regex = '''-----BEGIN PRIVATE KEY-----'''
tags = ["key", "private"]
[[rules]]
id = "Heroku API Key"
description = "Heroku API Key"
regex = '''(?i)heroku[\s]*[=:][\s]*['"]?[0-9a-fA-F]{32}['"]?'''
tags = ["key", "Heroku"]
[[rules]]
id = "JSON Web Token"
description = "JSON Web Token"
regex = '''eyJ[A-Za-z0-9-_=]+\.eyJ[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*'''
tags = ["token", "JWT"]

При ска­ниро­вании с исполь­зовани­ем такого набора пра­вил мы получи­ли 78 сек­ретов, из которых 46 ока­зались истинны­ми. Почему этот резуль­тат луч­ше пре­дыду­щего? Да потому, что пра­вила были написа­ны вруч­ную и охва­тили боль­шее количес­тво уте­чек, что, одна­ко, не изба­вило нас от лож­ных сра­баты­ваний.

Вот что получит­ся, если допол­нить эти пра­вила ана­лизом энтро­пии.

title = "Enhanced Gitleaks Configuration with Extended Entropy Analysis"
version = 2
[[rules]]
id = "AWS Access Key"
description = "AWS Access Key"
regex = '''AKIA[0-9A-Z]{16}'''
tags = ["key", "AWS"]
entropy = 3.5
[[rules]]
id = "AWS Secret Key"
description = "AWS Secret Key"
regex = '''(?i)aws(.{0,20})?['"][0-9a-zA-Z\/+]{40}['"]'''
tags = ["key", "AWS"]
entropy = 3.5
[[rules]]
id = "Google API Key"
description = "Google API Key"
regex = '''AIza[0-9A-Za-z-_]{35}'''
tags = ["key", "Google"]
entropy = 3.5
[[rules]]
id = "Slack Token"
description = "Slack Token"
regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})'''
tags = ["token", "Slack"]
entropy = 3.5
[[rules]]
id = "SSH Private Key"
description = "SSH Private Key"
regex = '''-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----'''
tags = ["key", "SSH"]
entropy = 3.5
[[rules]]
id = "Generic API Key"
description = "Generic API Key"
regex = '''(?i)(apikey|api_key|secret_key|client_secret|access_token)[\s]*[=:][\s]*['"]?[A-Za-z0-9\/+=-_]{32,64}['"]?'''
tags = ["key", "API"]
entropy = 3.5
[[rules]]
id = "Generic Secret"
description = "Generic Secret"
regex = '''(?i)(secret|password|pwd|token|key|auth)[\s]*[=:][\s]*['"]?[A-Za-z0-9\/+=-_]{8,128}['"]?'''
tags = ["secret"]
entropy = 3.5
[[rules]]
id = "Database Connection String"
description = "Database Connection String"
regex = '''(?i)(mongodb|postgres|mysql|sqlserver|redis|couchdb|oracle):\/\/[^\s]+'''
tags = ["database", "connection"]
entropy = 3.5
[[rules]]
id = "Google OAuth Client ID"
description = "Google OAuth Client ID"
regex = '''[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com'''
tags = ["oauth", "Google"]
entropy = 3.5
[[rules]]
id = "Google OAuth Client Secret"
description = "Google OAuth Client Secret"
regex = '''(?i)("client_secret":\s*["'][A-Za-z0-9-_]{24}["'])'''
tags = ["oauth", "Google"]
entropy = 3.5
[[rules]]
id = "Private Key"
description = "Private Key"
regex = '''-----BEGIN PRIVATE KEY-----'''
tags = ["key", "private"]
entropy = 3.5
[[rules]]
id = "Heroku API Key"
description = "Heroku API Key"
regex = '''(?i)heroku[\s]*[=:][\s]*['"]?[0-9a-fA-F]{32}['"]?'''
tags = ["key", "Heroku"]
entropy = 3.5
[[rules]]
id = "JSON Web Token"
description = "JSON Web Token"
regex = '''eyJ[A-Za-z0-9-_=]+\.eyJ[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*'''
tags = ["token", "JWT"]
entropy = 3.5
[[rules]]
id = "Twilio API Key"
description = "Twilio API Key"
regex = '''(?i)twilio[\s]*[=:][\s]*['"]?[A-Za-z0-9-_]{32}['"]?'''
tags = ["key", "Twilio"]
entropy = 3.5
[[rules]]
id = "Stripe API Key"
description = "Stripe API Key"
regex = '''(?i)sk_live_[0-9a-zA-Z]{24}'''
tags = ["key", "Stripe"]
entropy = 3.5
[[rules]]
id = "SendGrid API Key"
description = "SendGrid API Key"
regex = '''(?i)SG\.[0-9a-zA-Z\-_]{22}\.[0-9a-zA-Z\-_]{43}'''
tags = ["key", "SendGrid"]
entropy = 3.5
[[rules]]
id = "MailChimp API Key"
description = "MailChimp API Key"
regex = '''(?i)[0-9a-f]{32}-us[0-9]{1,2}'''
tags = ["key", "MailChimp"]
entropy = 3.5
[[rules]]
id = "GitHub Personal Access Token"
description = "GitHub Personal Access Token"
regex = '''ghp_[0-9a-zA-Z]{36}'''
tags = ["key", "GitHub"]
entropy = 3.5
[[rules]]
id = "GitLab Personal Access Token"
description = "GitLab Personal Access Token"
regex = '''glpat-[0-9a-zA-Z\-_]{20}'''
tags = ["key", "GitLab"]
entropy = 3.5
[[rules]]
id = "Azure Storage Account Key"
description = "Azure Storage Account Key"
regex = '''(?i)(AccountKey|AccountKeyPrimary|AccountKeySecondary|SharedAccessSignature)=([A-Za-z0-9+\/=]{88})'''
tags = ["key", "Azure"]
entropy = 3.5
[[rules]]
id = "Salesforce Security Token"
description = "Salesforce Security Token"
regex = '''[A-Za-z0-9]{24}'''
tags = ["token", "Salesforce"]
entropy = 3.5

Мы получи­ли 3810 уте­чек! Отку­да такой резуль­тат? Про­ект содер­жит име­на перемен­ных, политик и про­чие дан­ные, которые обла­дают высокой энтро­пией. Нап­ример, у наз­вания полити­ки AWSLoadBalancerController энтро­пия 3,7406015, а у AmazonEKSWorkerNodePolic — 4,0849624. На все эти и дру­гие име­на в исходных тек­стах и реаги­рует Gitleaks.

Ко­неч­но, в пра­вилах мож­но про­писать исклю­чения. Они дол­жны быть опи­саны в полях [allowlist] (для исклю­чения катало­гов или фай­лов) и [allowlist.keywords] (для исклю­чения клю­чевых слов), что в разы сок­ратит количес­тво лож­ных сра­баты­ваний.

Так­же в пра­вилах мож­но менять уро­вень энтро­пии, на которую реаги­рует Gitleaks. Нап­ример, если мы выс­тавим уро­вень 4.0, то получим уже 2912 уте­чек, а при 4.5 количес­тво сра­баты­ваний упа­дет до 126. С уче­том все­го выше­опи­сан­ного мы име­ем мак­сималь­но гиб­ко нас­тра­иваемый инс­тру­мент, который работа­ет как с ана­лизом энтро­пии, так и с регуляр­ными выраже­ниями.

Подводим итоги

Итак, мы рас­смот­рели два метода поис­ка уте­чек и три инс­тру­мен­та. Резуль­тат их срав­нения — в таб­лице ниже.

Ска­зать однознач­но, что ана­лиз энтро­пии луч­ше, чем regex, или наобо­рот, невоз­можно. Каж­дый метод дает лож­ные сра­баты­вания или не находит те или иные утеч­ки. Так что луч­шей прак­тикой будет исполь­зовать оба метода с тон­кой нас­трой­кой под собс­твен­ные тре­бова­ния.

Ре­гуляр­ные выраже­ния и ана­лиз энтро­пии прек­расно допол­няют друг дру­га: пер­вый метод точ­но бьет по кон­крет­ным целям, вто­рой вычис­ляет скры­тые пат­терны. Вмес­те они соз­дают мощ­ный дуэт, который поможет тебе обна­ружить даже самые замас­кирован­ные сек­реты.

Луч­шим инс­тру­мен­том по резуль­татам нашего неболь­шого ана­лиза стал Gitleaks, в нас­трой­ках которо­го ты можешь как писать собс­твен­ные пра­вила, так и выс­тавлять нуж­ный уро­вень энтро­пии. Но если нет воз­можнос­ти и желания нырять в пучину написа­ния кас­томных пра­вил, мож­но огра­ничить­ся Detect Secrets, который показал себя дос­таточ­но хорошо при пол­ном отсутс­твии допол­нитель­ных нас­тро­ек.

В сле­дующей статье мы пла­ниру­ем под­робнее рас­ска­зать про Gitleaks: раз­берем спо­собы написа­ния пра­вил, тон­кости нас­трой­ки, а так­же внед­рение это­го инс­тру­мен­та в CI/CD.