Asosiy kontentga o‘tish

Maqolalar 7 daqiqa 212 ko‘rish

Token, parol, kalit: sirlar qayerda yashaydi va qayerda o'ladi

GitHub'ga tushib qolgan bot tokeni bir necha daqiqada topiladi — buni skanerlash botlari tinimsiz qilib turadi. Sirlarni to'g'ri saqlash tartibini quramiz: .env fayllar, ruxsatlar, sizib chiqqandagi harakatlar rejasi va commit'dan oldingi himoya.

security devops

Mundarija

Kiberxavfsizlik darslarimda talabalarga bitta tajribani aytib beraman: GitHub'ga ochiq repo bilan tasodifan yuklangan token o'rtacha bir necha daqiqa ichida birinchi marta sinab ko'riladi. Buni maxsus botlar qiladi — ular GitHub'ning yangi commit oqimini tinimsiz skanerlashadi va token naqshlarini (Telegram, AWS, Stripe...) avtomatik ushlashadi. Ya'ni "kim ham mening kichkina repomni ko'rardi" degan umid ishlamaydi: ko'radigan tomon odam emas, mashina.

Seriya davomida sirlarga oid qoidalar bo'lak-bo'lak uchrab keldi — systemd'da EnvironmentFile, CI'da Secrets. Yakuniy qismda hammasini bitta tizimga yig'amiz.

Asosiy qoida: sir kodda emas, muhitda#

Sirning kodda yashashiga birinchi qadam doim beg'ubor ko'rinadi: "hozircha shu yerga yozib turay, keyin olib tashlayman". Keyin u commit bo'ladi — va bo'ldi, endi u tarixda. Shuning uchun qoida murosasiz: token, parol, kalit — faqat muhit o'zgaruvchisida. Kod ularni nomi bilan so'raydi, qiymatini qayerdan kelishi bilan ishi yo'q:

Python
# config/settings.py
import os

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]  # yo'q bo'lsa — ataylab yiqilsin
BOT_TOKEN = os.environ.get("BOT_TOKEN", "")  # ixtiyoriy bo'lsa — bo'sh default

os.environ["..."] bilan os.environ.get("...") orasidagi tanlov ham ongli: ilova ishlashi uchun majburiy sir yo'q bo'lsa, start paytida baland ovozda yiqilgani yaxshi — jimgina bo'sh qiymat bilan ishlab, qayeridadir g'alati xato berganidan ko'ra.

.env fayl va uning egizagi#

Muhit o'zgaruvchilarini qo'lda eksport qilib yurish noqulay, shuning uchun ular .env faylga yig'iladi. Bu faylning ikkita temir qoidasi bor.

Birinchisi — .env repo'ga hech qachon tushmaydi. Buning uchun u loyihaning birinchi kunidayoq .gitignore ga yoziladi:

.gitignore
.env

.gitignore faqat hali kuzatilmayotgan fayllarga ta'sir qiladi. Agar .env allaqachon commit qilingan bo'lsa, qatorni qo'shishning o'zi yetmaydi — faylni Git kuzatuvidan chiqarish kerak (diskdagi fayl o'chmaydi):

Terminal
git rm --cached .env
git commit -m ".env ni Git kuzatuvidan chiqarish"

Lekin unutmang: bu faqat keyingi commit'larni himoya qiladi, tarixdagi sirlar joyida qoladi. Ular bilan nima qilish kerakligi pastdagi "Sizib chiqdi" bo'limida.

Ikkinchisi — .envning "egizagi": qiymatlarsiz, lekin to'liq ro'yxatli .env.example fayli repo'da turadi:

Terminal
# .env.example — bu fayl repo'da ochiq turadi, sirlar YO'Q
DJANGO_SECRET_KEY=
BOT_TOKEN=
DATABASE_URL=postgresql://user:password@127.0.0.1/dbname
TELEGRAM_ADMIN_CHAT_ID=

Bu kichik fayl ikki katta muammoni yechadi. Yangi muhit ko'targan odam (yoki olti oydan keyingi siz) qaysi o'zgaruvchilar kerakligini kod ichini titkilamasdan biladi. Va CI/CD qismida aytilgan env drift — kodga yangi o'zgaruvchi qo'shilib, serverdagi .env unutilishi — ushlanadigan bo'ladi: .env.example bilan serverdagi faylni solishtirish kifoya. Qiymatlarni emas, faqat nomlarni solishtiramiz, shunda sirlar ekranga chiqmaydi:

Terminal
# serverda, loyiha papkasida
diff <(grep -o '^[A-Za-z_][A-Za-z0-9_]*=' .env.example | sort) \
     <(grep -o '^[A-Za-z_][A-Za-z0-9_]*=' .env | sort)

Masalan, serverdagi .env ga TELEGRAM_ADMIN_CHAT_ID yozish unutilgan bo'lsa:

Natija
4d3
< TELEGRAM_ADMIN_CHAT_ID=

< belgili qator — .env.example da bor, lekin serverdagi .env da yo'q o'zgaruvchi. Hech narsa chiqmasa, ikkala fayldagi nomlar bir xil.

Serverda .env ni kod o'zi o'qimaydi: uni systemd qismida ko'rgan EnvironmentFile= qatori xizmat ishga tushishidan oldin muhitga yuklaydi. Lokal kompyuterda esa bu ishni kutubxona bajaradi — Django uchun qanday qilinishi alohida maqolada bor. Busiz python manage.py runserver KeyError: 'DJANGO_SECRET_KEY' bilan yiqiladi — yuqorida aynan shuni xohlagan edik.

Serverda esa .env fayli o'z uy tartibiga ega:

Terminal
sudo chown deploy:deploy /opt/mysite/.env
sudo chmod 600 /opt/mysite/.env    # faqat egasi o'qiydi — boshqa hech kim

Sizib chiqdi: birinchi soat rejasi#

Ehtiyotkorlikka qaramay sir oshkor bo'lishi mumkin: commit'da ketdi, skrinshotda ko'rindi, chatga tashlab yuborildi. Bu vaziyatda ketma-ketlik oldindan ma'lum bo'lishi kerak, chunki o'ylab o'tirishga vaqt yo'q:

  1. Avval almashtiring, keyin tozalang. Birinchi harakat — sirni bekor qilish: bot tokenini @BotFather'da /revoke, API kalitni provayder panelida yangilash, parolni almashtirish. Repo'ni tozalash ikkinchi o'rinda — chunki sizdan oldin allaqachon nusxa olishgan deb hisoblang;
  2. Yangi sirni joylang — serverdagi .env, GitHub Secrets;
  3. Tarixni tozalang — lekin illyuziyasiz.

git'da o'chirish — o'chirish emas

Keyingi commit'da sirni olib tashlash uni yashirmaydi: u tarixda, har klonda, har fork'da qolgan. Tarixni git filter-repo yoki BFG bilan qayta yozish mumkin, lekin bu ham faqat sizning repoingizni tozalaydi — allaqachon tortib olingan nusxalarni emas. Shuning uchun tartib qat'iy: sizib chiqqan sir — o'lgan sir, uni tozalash emas, almashtirish qutqaradi.

Commit'dan oldingi himoya#

Eng yaxshi sizish — bo'lmagan sizish. Bir nechta bepul qatlamni yoqib qo'ying.

Birinchi qatlam — gitleaks. U fayllar va commit'lardan sir naqshlarini qidiradi. O'rnatish: macOS'da brew install gitleaks, Linux va Windows uchun tayyor fayl releases sahifasida.

Terminal
# butun Git tarixini bir marta tekshirib chiqish
gitleaks git --redact .

--redact topilgan sirni ekranga chiqarmaydi — aks holda tekshiruvning o'zi sirni terminal oynasida va CI loglarida ochiq ko'rsatib qo'yadi.

Qo'lda eslab yurmaslik uchun uni commit'dan oldin avtomatik ishlaydigan qilib qo'yamiz. Loyiha papkasida .git/hooks/pre-commit faylini yarating:

.git/hooks/pre-commit
#!/bin/sh
# faqat commit'ga tayyorlangan (staged) o'zgarishlarni tekshiradi
gitleaks git --pre-commit --staged --redact --no-banner .
Terminal
chmod +x .git/hooks/pre-commit

Endi sir topilsa, gitleaks leaks found: 1 deb yozadi va commit yaratilmaydi. Bu fayl .git ichida yotgani uchun repo bilan birga tarqalmaydi — har bir kompyuterda alohida qo'yiladi.

Skaner — xavfsizlik to'ri, qoida emas

Gitleaks sirni naqsh va kalit so'z bo'yicha taniydi. Gitleaks 8.30 bilan tekshirilganda TELEGRAM_BOT_TOKEN = "..." va GitHub'ning ghp_... tokeni ushlandi, lekin xuddi shu Telegram tokeni BOT_TOKEN = "..." nomi bilan yozilganda ham, Django'ning SECRET_KEY qiymati ham o'tib ketdi. Shuning uchun asosiy himoya — yuqoridagi qoida: sir kodga umuman yozilmaydi.

Ikkinchi qatlam — CI. Hook'ni o'rnatishni unutgan kompyuterdan kelgan push'ni CI/CD qismidagi checks job'i ushlaydi. Unga gitleaks qadamini qo'shamiz; butun tarixni ko'rishi uchun checkout'ga fetch-depth: 0 kerak:

YAML
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0             # faqat oxirgi commit emas, butun tarix
      - uses: gitleaks/gitleaks-action@v3
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Shaxsiy akkauntdagi repo uchun shu yetarli. Repo tashkilot (organization) akkauntiga tegishli bo'lsa, gitleaks sayti bepul beradigan GITLEAKS_LICENSE kalitini ham Secrets'ga qo'shish kerak.

Uchinchi qatlam — GitHub push protection. Repo sahifasida Settings → Advanced Security → Push protection ni yoqing: GitHub tanigan naqshdagi sir push qilinsa, uni qabul qilmay qaytaradi. Ochiq repolarda bepul, yoqmaslikka sabab yo'q.

Nima .env'da, nima unda emas#

Oxirida bitta chegara masalasi. Hamma narsani ham sir deb yurmang — aksincha, konfiguratsiya bilan sirni ajratish tartib beradi:

.env'da (sir) Kodda/repo'da (konfiguratsiya)
SECRET_KEY, tokenlar, parollar Port raqamlari, timeout'lar
Baza ulanish satri (paroli bilan) ALLOWED_HOSTS ro'yxati
Tashqi API kalitlari Kesh muddatlari, sahifa o'lchamlari

Sir bo'lmagan narsani .envga olib o'tish teskari muammo tug'diradi: konfiguratsiya ko'zdan yo'qoladi, muhitlar orasidagi farq esa hujjatsiz qoladi.

Seriya yakuni#

To'qqiz qismlik yo'l shu yerda tugaydi. Yalang'och VPS'dan boshlagan edik — endi qo'lingizda to'liq tizim bor: SSH kalitli kirish va firewall, systemd ostidagi xizmatlar, nginx va TLS, timer'li zaxira, reboot'ga chidamlilik, o'zi deploy bo'ladigan pipeline, o'qiladigan loglar va joyida turgan sirlar. Bularning har biri alohida mayda ko'rinadi, birga esa "kechasi xotirjam uxlaydigan server" degan natijani beradi.

Savollar bo'lsa — bog'laning, qaysidir qadam o'z serveringizda boshqacha chiqqan bo'lsa, yozing: seriya jonli, real savollar asosida to'ldirilib boradi.

7 daqiqa 212 marta o‘qildi