RE:NODE

ბაზები14 წუთის საკითხავი

მონაცემთა ბაზის უსაფრთხოების ჩეკლისტი: წვდომა, როლები, backup

მონაცემთა ბაზის მნიშვნელოვანი შემოწმებები: რა ჩანს გარედან, ვის შეუძლია შესვლა, რა უფლებები აქვს, TLS, injection, ლიმიტები და backup, რომელიც რეალურად აღგიდგენია.

0 მკითხველი

მონაცემთა ბაზებს იშვიათად ტეხავენ. ხშირად უბრალოდ შიგნით შედიან. ინციდენტების დიდი ნაწილი ოთხ რამეზე დადის: პორტს მთელი ინტერნეტი ხედავდა, პაროლი გამოსაცნობი ან განმეორებადი იყო, ერთი ყველაფრის შემძლე ანგარიში სისტემის ყველა საქმეს აკეთებდა, და როცა რაღაც არასწორად წავიდა, აღსადგენი backup არ არსებობდა. უსაფრთხოების ლიტერატურაში ყველა ჭკვიანური რამ ამ ოთხის უკან დგას, და თუ მხოლოდ ესენს გამოასწორებ, პროდაქშენ სისტემათა უმეტესობაზე წინ იქნები.

ეს არის ჩეკლისტი, რომელსაც ერთ შუადღეში გაივლი, იმ თანმიმდევრობით, რომელიც ყველაზე მეტ რისკს პირველად აქრობს. მაგალითებისთვის PostgreSQL და MongoDB გამოვიყენე, რადგან ეს ის ორი ძრავაა, რომელსაც ხალხი ყველაზე ხშირად თვითონ უშვებს, მაგრამ ფორმა ნებისმიერი ბაზისთვის იგივეა: გადაწყვიტე, ვის შეუძლია მასთან მიღწევა, ვის შეუძლია შესვლა, რას აკეთებს თითოეული ანგარიში, დაშიფრე გზა, შეზღუდე ზიანი, რომელიც ერთ კლიენტს შეუძლია მიაყენოს, და შეინახე ასლი, რომლის აღდგენაც დამტკიცებული გაქვს.

ერთი ჩარჩო, რომელიც გზაში გაითვალისწინე. უსაფრთხოება ბოლოს დამატებული თვისება არ არის - ეს გადაწყვეტილებების ერთობლიობაა იმაზე, თუ რამდენად შორს მიდის ზიანი. ყველა შეცდომას ვერ აიცილებ. თითოეული ნაბიჯი პასუხობს კითხვას: როცა რამე არასწორად წავა, რამდენად შორს მივა.

წვდომა ქსელიდან: პირველი და უდიდესი მოგება#

ყველა ბაზა, რომელიც საჯარო მისამართზე უსმენს, აუცილებლად იპოვება. არა "შეიძლება იპოვონ" - აუცილებლად. მასობრივი სკანერები განუწყვეტლივ ავლებენ მთელ მისამართთა სივრცეს 5432, 27017, 3306 და 6379 პორტებზე, და ახალ ჰოსტს ღია პორტით პირველი შესვლის მცდელობა ჩვეულებრივ ჩართვიდან რამდენიმე წუთში ხვდება. 2017 წლის MongoDB-ს გამოძალვის ტალღა ჭკვიანური ექსპლოიტი არ ყოფილა - ეს იყო ათასობით ინსტანცია, 0.0.0.0-ზე მიბმული და გამორთული ავტორიზაციით.

დაიწყე იმის გარკვევით, რა უსმენს სინამდვილეში:

bash
$ ss -ltnpState  Recv-Q Send-Q Local Address:Port  ProcessLISTEN 0      244    127.0.0.1:5432      users:(("postgres",pid=812,fd=6))LISTEN 0      4096   0.0.0.0:27017       users:(("mongod",pid=944,fd=11))

127.0.0.1:5432 მხოლოდ თვით მანქანიდან ჩანს. 0.0.0.0:27017 ჩანს ყველგან, სადაც firewall-ი უშვებს. შემდეგ შეამოწმე გარედან, რადგან იმას, რასაც მანქანა თვლის, და იმას, რასაც ქსელი აკეთებს, სხვადასხვა პასუხი აქვს:

bash
$ nc -vz db.example.net 5432Connection to db.example.net 5432 port [tcp/postgresql] succeeded!

პარამეტრები, რომლებიც ამას აკონტროლებს:

ძრავაპარამეტრიუსაფრთხო ნაგულისხმევი
PostgreSQLlisten_addresses ფაილში postgresql.conflocalhost, ან ერთი კერძო მისამართი
PostgreSQLpg_hba.conf-ის host წესებიკონკრეტული მისამართები, არასოდეს 0.0.0.0/0
MongoDBnet.bindIp ფაილში mongod.conf127.0.0.1 და კონკრეტული მისამართები
ნებისმიერიFirewallშემომავალი ყველაფერი აკრძალულია, დასახელებული წყაროები დაშვებულია

თუ აპლიკაცია და ბაზა ერთ მანქანაზეა, მიაბი localhost-ს და ამ თავის კითხვა შეწყვიტე. თუ არა, დაუშვი ზუსტად ის მისამართები, რომლებსაც ეს სჭირდება, და სხვა არაფერი. Firewall-ის წესები, რომლებსაც მნიშვნელობა აქვს გასწავლის ამ წესების დაწერას საკუთარი თავის გარეთ დარჩენის გარეშე, ხოლო PostgreSQL-ის დისტანციური კავშირები გვიჩვენებს სამ პარამეტრს, რომლებიც უნდა დაემთხვეს, სანამ დისტანციური კლიენტი საერთოდ დაკავშირდება.

ავტენტიფიკაცია, რომელიც გამოსაცნობი არ არის#

როცა პორტს მხოლოდ ისინი აღწევენ, ვისაც სჭირდებათ, შემდეგი კითხვაა, ვის შეუძლია შესვლა.

PostgreSQL ამას წყვეტს pg_hba.conf-ით, რომელიც იკითხება ზემოდან ქვემოთ და პირველივე შესაბამისი ხაზი იმარჯვებს. სწორედ ეს თანმიმდევრობა ხვდება ხალხს ხაფანგში: ნებადამრთველი ხაზი შემზღუდველის ზემოთ ნიშნავს, რომ შემზღუდველი არასოდეს სრულდება.

pg_hba.conf
# TYPE    DATABASE  USER     ADDRESS           METHODlocal     all       postgres                   peerhostssl   app       app_rw   10.0.0.0/24       scram-sha-256hostssl   app       app_ro   10.0.0.0/24       scram-sha-256host      all       all      0.0.0.0/0         reject

გამოიყენე scram-sha-256 და არა md5, და არასოდეს trust, რაც პაროლის სრულ არარსებობას ნიშნავს. მომხმარებლების შექმნამდე დააყენე password_encryption = scram-sha-256, თორემ მათი პაროლები ძველი პარამეტრის მიხედვით შეინახება. hostssl host-ის ნაცვლად უარყოფს კავშირს, თუ ის დაშიფრული არ არის, რაც უფრო ძლიერია, ვიდრე კლიენტისთვის თავაზიანად თხოვნა.

MongoDB წვდომის კონტროლის გარეშე მოდის და ეს mongod.conf-ის ყველაზე მნიშვნელოვანი ხაზია:

mongod.conf
security:  authorization: enablednet:  bindIp: 127.0.0.1,10.0.0.5  port: 27017

მის გარეშე ადმინისტრატორია ყველა, ვინც პორტს მიაღწევს. მასთან MongoDB იყენებს SCRAM-SHA-256-ს და ყოველ ოპერაციას მომხმარებელი სჭირდება.

თავად პაროლებისთვის: გენერირებული, გრძელი, თითოეულ ბაზაზე უნიკალური, password manager-ში შენახული და staging-სა და production-ს შორის არასოდეს გამეორებული. გენერატორიდან აღებული ოცი შემთხვევითი სიმბოლო სჯობს ჩანაცვლებებიანი დასამახსოვრებელ ფრაზას, რადგან თავდამსხმელის ლექსიკონი ამ ჩანაცვლებებს უკვე შეიცავს. თუ პაროლი ოდესმე ჩატში, ticket-ში ან screenshot-ში ჩასვი, ის დამწვარია - შეცვალე.

ერთი მომხმარებელი - ერთი საქმე#

ეს ნაბიჯი აქცევს გატეხვას ინციდენტად და არა კატასტროფად, და სწორედ ის გამოტოვება ყველაზე ხშირად, რადგან ერთი superuser კავშირის სტრიქონში ყოველთვის მუშაობს.

აპლიკაციას runtime-ზე ცხრილების შექმნა არ სჭირდება. ანალიტიკის დაფას სტრიქონების წაშლა არ სჭირდება. მიგრაციის ხელსაწყოს სქემის უფლებები თვეში ოთხმოცდაათი წამით სჭირდება და არა მუდმივად. ოთხი როლი სისტემათა უმეტესობას ფარავს:

როლიუფლებებივინ იყენებს
Owner ან superuserყველაფერიარავინ ყოველდღიურად. ინახება საგანგებო შემთხვევისთვის
მიგრაციის მომხმარებელისქემის ცვლილებები ერთ ბაზაზემხოლოდ deploy pipeline
აპლიკაციის მომხმარებელიცხრილებზე წაკითხვა და ჩაწერა, DDL-ის გარეშეგაშვებული აპლიკაცია
მხოლოდ წაკითხვის მომხმარებელიმხოლოდ SELECTდაფები, ანგარიშგება, ადამიანები, რომლებიც უბრალოდ იხედებიან

PostgreSQL-ში ეს ასე გამოიყურება:

sql
CREATE ROLE app_rw LOGIN PASSWORD 'generated-here';CREATE ROLE app_ro LOGIN PASSWORD 'a-different-one';GRANT CONNECT ON DATABASE app TO app_rw, app_ro;GRANT USAGE ON SCHEMA public TO app_rw, app_ro;GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_rw;GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_rw;GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_ro;ALTER DEFAULT PRIVILEGES IN SCHEMA public  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_rw;ALTER DEFAULT PRIVILEGES IN SCHEMA public  GRANT SELECT ON TABLES TO app_ro;

ALTER DEFAULT PRIVILEGES ხაზები ის არის, რასაც ხალხი ივიწყებს. მათ გარეშე შემდეგი მიგრაციით შექმნილი ყველა ცხრილი აპლიკაციის მომხმარებლისთვის უხილავია და ღამის სამ საათზე production-ში permission შეცდომას იღებ. PostgreSQL-ის როლები და უფლებები მთელ მოდელს გადის, იმის ჩათვლით, თუ რატომ აქვს PUBLIC-ს ძველ ვერსიებზე მოსალოდნელზე მეტი უფლება.

MongoDB-ში იგივე იდეა ერთი ბაზით შემოფარგლულ ჩაშენებულ როლებს იყენებს:

javascript
db.createUser({  user: "app_rw",  pwd: passwordPrompt(),  roles: [ { role: "readWrite", db: "app" } ]})

აპლიკაციას არასოდეს მისცე root, dbOwner ან რამე, რაც AnyDatabase-ით მთავრდება. შემდეგ კავშირის სტრიქონს authSource სჭირდება იმ ბაზაზე მითითებით, სადაც მომხმარებელი შეიქმნა, და ეს არის ყველაზე გავრცელებული მიზეზი, რის გამოც სწორი პაროლი უარყოფილია - MongoDB-ის connection string-ები მთელ აგებულებას აჩვენებს.

იგივე პრინციპი ადამიანებზეც მოქმედებს. პანელის ანგარიშებს, deploy გასაღებებსა და დაფებს თითოეულს უნდა ჰქონდეს ყველაზე ვიწრო როლი, რომელიც სამუშაოს ასრულებინებს, და დასახელებული მფლობელი. Subuser-ები და მინიმალური უფლებები ამ მხარეს განიხილავს.

დაშიფრე კავშირი და გადაამოწმე სერტიფიკატი#

თუ ბაზა და აპლიკაცია ერთ მანქანაზე არ არის, ავტორიზაციის მონაცემები და ყოველი სტრიქონი ქსელს გადის. მისი დაშიფვრა ადვილია. ისე დაშიფვრა, რომ ნამდვილად დაამტკიცოს, ვის დაუკავშირდი, ერთ დამატებით ნაბიჯს მოითხოვს, და კავშირის სტრიქონების უმეტესობა მანამდე ჩერდება.

PostgreSQL-ის sslmode-ს ექვსი მნიშვნელობა აქვს და მხოლოდ ორი ღირს გამოსაყენებლად:

sslmodeშიფრავსსერვერს ამოწმებსვერდიქტი
disableარაარაღია ტექსტი
allow, preferშესაძლოაარაprefer ნაგულისხმევია და ჩუმად უკან ბრუნდება
requireდიახარადაუცველია შუაში მდგარი მანქანის მიმართ
verify-caდიახმხოლოდ სერტიფიკატების ჯაჭვსმისაღებია
verify-fullდიახჯაჭვსა და hostname-სგამოიყენე ეს
code
postgresql://app_rw:pw@db.example.net:5432/app?sslmode=verify-full&sslrootcert=/etc/ssl/certs/ca.pem

MongoDB-ზე იგივე არგუმენტია, სხვა დაწერილობით: tls=true URI-ში, tlsCAFile, თუ სერტიფიკატი საჯარო ორგანოსგან არ არის, და არასოდეს tlsAllowInvalidCertificates=true, რომელიც ვერიფიკაციას თიშავს, ხოლო სტრიქონში სიტყვა TLS გამშვიდებისთვის რჩება.

ავტორიზაციის მონაცემები კოდს მოაცილე#

ბაზის პაროლი git რეპოზიტორიაში არის პაროლი ინტერნეტში, რეპოზიტორია საჯაროა თუ არა - ის რჩება ისტორიაში, fork-ებში, ყველას laptop-ის backup-ებში, ვინც ოდესმე clone გააკეთა, და იმ ინდექსებში, რომლებსაც შენი git ჰოსტი ინახავს. ავტორიზაციის მონაცემები ეკუთვნის გარემოს ცვლადებს ან secrets საცავს, runtime-ზე შეყვანილს, და .env უნდა იყოს .gitignore-ში პირველი commit-დან და არა იმ დღიდან, როცა შენიშნავ.

სამი პრაქტიკული წესი:

  • პაროლი არასოდეს ჩაწერო command line-ზე. ის ხვდება shell-ის ისტორიაში და მანქანის ყველა მომხმარებლისთვის ps-ის გამოტანაში. გამოიყენე ~/.pgpass რეჟიმით 0600, PGPASSWORD გარემოში, ან მოთხოვნა.
  • staging-სა და production-ს ყოველთვის სხვადასხვა ავტორიზაციის მონაცემები ჰქონდეს. staging მანქანა განსაზღვრებით ნაკლებად სანდოა, და საერთო პაროლი მას შესასვლელად აქცევს.
  • როცა ვინმე გუნდს ტოვებს, შეცვალე. გაუქმებული წვდომა და დავიწყებული წვდომა ერთი და იგივე არ არის.

გარემოს ცვლადები და secrets განიხილავს მექანიკას პანელის ჰოსტზე, სადაც Startup ჩანართი მნიშვნელობებს ინახავს და ისინი image-შიც და რეპოზიტორიაშიც არ არის.

მოთხოვნები, რომლებშიც injection ვერ შეაღწევს#

Injection ათწლეულების შემდეგაც ყველაზე გავრცელებული გზაა, რომლითაც ბაზას კითხულობს ის, ვისაც არ უნდა ეკითხა. მექანიზმი ყოველთვის ერთია: მომხმარებლის შეყვანა მოთხოვნას ეწებება, ამიტომ შეყვანას შეუძლია მოთხოვნის სტრუქტურა შეცვალოს და არა მხოლოდ მისი მნიშვნელობები.

javascript
// Broken. An email of  ' OR 1=1 --  returns every user.const sql = "SELECT * FROM users WHERE email = '" + email + "'";// Correct. The driver sends the query and the value separately.await client.query("SELECT * FROM users WHERE email = $1", [email]);
python
# psycopg, the same idea. The second argument is never string formatting.cur.execute("SELECT * FROM users WHERE email = %s", (email,))

პარამეტრიზებული მოთხოვნები escaping-ის ხრიკი არ არის, ისინი პროტოკოლის შესაძლებლობაა: ჯერ განცხადება იპარსება, შემდეგ მნიშვნელობები უერთდება, ამიტომ მნიშვნელობა სინტაქსად ვერ იქცევა. გამოიყენე ისინი ყველგან, იმ მოთხოვნისთვისაც კი, რომელიც აშკარად უსაფრთხოდ მიგაჩნია.

ორი რამ, რასაც პარამეტრები ვერ აკეთებს და სადაც injection უკან ბრუნდება:

  • იდენტიფიკატორები. ცხრილისა და სვეტის სახელები პარამეტრები ვერ იქნება. თუ დალაგების სვეტი query string-იდან მოდის, შეადარე ცნობილი სვეტების სახელების დაშვებულ სიას და დანარჩენი უარყავი. არასოდეს ჩასვა პირდაპირ.
  • მთელი clause-ები. WHERE ფრაგმენტების სტრიქონების შეერთებით აწყობა იგივე შეცდომაა უკეთეს ტანსაცმელში, ORM-ით იქნება თუ მის გარეშე. ORM-ების უმეტესობა ნაგულისხმევად უსაფრთხოა და აღარ არის, როგორც კი raw-SQL გასასვლელს გამოიყენებ.

MongoDB-ს საკუთარი ვერსია აქვს. თუ JSON მოთხოვნის სხეული პირდაპირ query დოკუმენტში გადადის, კლიენტს შეუძლია გამოგზავნოს {"password": {"$ne": null}} და ყველა ჩანაწერს დაემთხვეს. შემომავალი მნიშვნელობები დააკასტე მოსალოდნელ ტიპზე, სანამ მოთხოვნამდე მივა, და გამორთე სერვერზე JavaScript-ის შესრულება, იმის იმედად ყოფნის ნაცვლად, რომ $where ფრთხილად გამოიყენება.

ეს თავი იმიტომ დგას მინიმალური უფლებების შემდეგ, რომ ეს ორი ერთმანეთს ემატება. injection ანგარიშზე, რომელსაც მხოლოდ სამი ცხრილიდან SELECT შეუძლია, ცუდი დღეა. იგივე injection superuser-ზე კი ფაილების ჩაწერასა და ბრძანებების გაშვებას შეძლებს.

ლიმიტები, რომ ერთმა კლიენტმა ბაზა ვერ დააგდოს#

ხელმისაწვდომობა უსაფრთხოების ნაწილია, და პატარა ბაზის გათიშვის ყველაზე ადვილი გზაა მასთან იმდენი კავშირის გახსნა, სანამ თავისუფალი აღარ დარჩება.

  • `max_connections` PostgreSQL-ში მკაცრი ზღვარია, და თითოეული კავშირი მეხსიერებას ხარჯავს, მუშაობს თუ უსაქმოდაა. 1-2 GB ინსტანციაზე 100 უკვე ოპტიმისტურია. წინ pooler დააყენე და თითოეულ აპლიკაციას საკუთარი CONNECTION LIMIT მიეცი ბრძანებით ALTER ROLE app_rw CONNECTION LIMIT 20;. Connection pool-ები და ლიმიტები არითმეტიკას განმარტავს.
  • `statement_timeout` ერთ გაუკონტროლებელ მოთხოვნას რესურსების სამუდამოდ დაკავებას უშლის. დააყენე როლის დონეზე და არა გლობალურად, რომ ანგარიშგების მომხმარებელს ვებ აპლიკაციაზე უფრო გრძელი ლიმიტი ჰქონდეს: ALTER ROLE app_rw SET statement_timeout = '15s';
  • `idle_in_transaction_session_timeout` კლავს სესიებს, რომლებმაც ტრანზაქცია გახსნეს და წავიდნენ. ისინი vacuum-ს ბლოკავენ და lock-ებს იჭერენ, და შეცდომიანი ვებ აპლიკაცია მათ ასობით აწარმოებს.
  • Rate limit-ები აპლიკაციაში ყველაფრის წინ, რაც ანონიმური ვიზიტორისთვის ძვირ მოთხოვნას ასრულებს. ძიების endpoint-ები ჩვეულებრივი მსხვერპლია. Rate limit-ები და abuse ამ შაბლონს აღწერს.

Backup, რომელიც რეალურად აღგიდგენია#

Backup, რომელიც არავის აღუდგენია, ჰიპოთეზაა. ეს ჩეკლისტის ბოლო ხაზია და ის, რომელიც წყვეტს, ინციდენტი უხერხულობა იქნება თუ ბიზნესის დასასრული.

  1. ავტომატური, გრაფიკით. ხელით backup ის backup-ია, რომელსაც დატვირთულ კვირას შეწყვეტ, როცა ყველაზე მეტად დაგჭირდება.
  2. იმ მანქანის გარეთ, რომელსაც იცავს. იმავე დისკზე ასლი წაშლილ ცხრილს გადაურჩება და სხვა არაფერს.
  3. ერთზე მეტი თაობა. გაფუჭება და მავნე ცვლილებები ხშირად დღეების შემდეგ შეინიშნება, და ერთი ღამის ასლი იმ დროისთვის კარგს გადაფარავს.
  4. აღდგენილი განზრახ, შენთვის მოსახერხებელ დროს. თვეში ან ორ თვეში ერთხელ აღადგინე დროებით ბაზაში, დათვალე რამდენიმე სტრიქონი, გაუშვი აპლიკაცია მასზე. ეს ერთადერთი მტკიცებულებაა, რომ backup მუშაობს.
  5. განიხილება როგორც მგრძნობიარე. dump ფაილი მთელი ბაზაა ერთ ჩამოსატვირთ ობიექტში. ნუ დატოვებ მას ვებიდან ხელმისაწვდომ დირექტორიაში, რაც გასაკვირად გავრცელებული გზაა, რომლითაც საიტები ყველაფერს ჟონავენ.

Database backup-ები და აღდგენა ძრავების მიხედვით მექანიკას აჩვენებს, ხოლო აღდგენის შემოწმება, სანამ დაგჭირდება ნახევარია, რომელსაც ხალხი ტოვებს. თუ უარესი უკვე მოხდა, რა უნდა გააკეთო, როცა შენი სერვერი გატეხეს აღწერს, რა თანმიმდევრობით იმოქმედო, და ეს ინსტინქტის გამოთქმულ თანმიმდევრობას არ ემთხვევა.

ლოგები, რომლებიც აჩვენებს, რა შეიცვალა#

შეუძლებელია იმის გამოძიება, რაც არ ჩაგიწერია, და უმეტეს ბაზაზე ნაგულისხმევი ლოგირება თითქმის არაფერ სასარგებლოს წერს.

postgresql.conf
log_connections = onlog_disconnections = onlog_statement = 'ddl'log_min_duration_statement = 1000log_line_prefix = '%m [%p] %q%u@%d from %h '

log_statement = 'ddl' წერს ყოველ სქემის ცვლილებას ყველა მოთხოვნის ლოგირების ხმაურის გარეშე. log_min_duration_statement = 1000 წერს ყველაფერს, რაც წამზე ნელია, და ამავდროულად შენი წარმადობის მონაცემია. %h პრეფიქსში ყოველ ხაზზე კლიენტის მისამართს ათავსებს, რაც პირველი გჭირდება, როცა რაღაც უცნაურად გამოიყურება.

ძრავის გარდა, თვალი ადევნე იმას, რაც იშვიათად იცვლება: ახალი როლი, შეცვლილი pg_hba.conf, მომხმარებელი, რომელსაც უფრო მეტი უფლება მიეცა, ვიდრე ჰქონდა. ესენი პატარა მოვლენებია დიდი მნიშვნელობით. ლოგები, რომლებიც ღირს შენახვად შენახვის ვადებს განიხილავს, ხოლო პანელის თითოეული სერვერის activity ლოგი ანგარიშის მხარეს წერს, ვინ რა გააკეთა.

ჩეკლისტი#

გაიარე ერთხელ ყოველი ბაზისთვის, რომელსაც უშვებ. რასაც ვერ უპასუხებ, ის არის შემდეგი გასასწორებელი.

#შემოწმებადასრულებულია, როცა
1პორტი მთელ მსოფლიოს არ ეხსნებაss -ltnp და გარე პორტის ტესტი ერთმანეთს ემთხვევა
2ავტენტიფიკაცია ჩართულია და SCRAM-ს იყენებსარც trust, არც md5, არც MongoDB authorization-ის გარეშე
3პაროლები გენერირებულია და უნიკალურიაარაფერი მეორდება გარემოებს შორის
4აპლიკაციის მომხმარებელს სქემის შეცვლა არ შეუძლიამიგრაციები სხვა როლით სრულდება
5ადამიანებისა და დაფებისთვის არსებობს მხოლოდ წაკითხვის როლიარავინ იყენებს owner-ს მოთხოვნებისთვის
6კავშირები დაშიფრულია და გადამოწმებულიაverify-full ან tls=true CA ფაილით
7ავტორიზაციის მონაცემები რეპოზიტორიის გარეთაა.env იგნორირებულია, მნიშვნელობები runtime-ზე შედის
8ყველა მოთხოვნა პარამეტრიზებულიასტრიქონების შეერთების გარეშე, იდენტიფიკატორები დაშვებულ სიაშია
9კავშირებისა და მოთხოვნების ლიმიტები დაყენებულიაერთ ცუდ კლიენტს სერვერის ამოწურვა არ შეუძლია
10Backup-ები ავტომატურია, მანქანის გარეთაა და შემოწმებულიაამ კვარტალში ერთი აღადგინე
11კავშირები, DDL და ნელი მოთხოვნები ილოგებაგუშინდელის აღდგენა შეგიძლია
12ძრავისა და დრაივერის ვერსიები აქტუალურიაუსაფრთხოების გამოშვებები კვირებში ინერგება

FAQ#

საკმარისია ძალიან გრძელი პაროლი, თუ პორტი საჯაროა?

ის გამოცნობას აჩერებს და სხვა არაფერს. საჯარო პორტი მაინც გხდის დაუცველს იმ ვერსიის პროტოკოლის დონის შეცდომების მიმართ, რასაც უშვებ, სხვაგან გაჟონილი ავტორიზაციის მონაცემების მიმართ და კავშირების ამოწურვით service-ის შეფერხების მიმართ. ამიტომ წყარო მისამართებიც შეზღუდე, ყოველთვის. ავტენტიფიკაცია და ხელმისაწვდომობა ცალკე კონტროლებია და ორივე გჭირდება.

მჭირდება TLS, თუ ბაზა კერძო ქსელშია?

მაინც გამოიყენე. კერძო ქსელები სხვა tenant-ებთანაც ისე ხშირად იზიარება, როგორც სახელი არ ეტყობა, გატეხილ შიდა მანქანას ტრაფიკის მოსმენა შეუძლია, და TLS-ის ჩართვის ფასი კავშირის სტრიქონში ერთი ხაზია. ერთადერთი, რაზეც ფრთხილად უნდა იყო, ვერიფიკაციაა: require verify-full-ის გარეშე შიფრავს, მაგრამ არ ამტკიცებს, ვინ უპასუხა.

იცავს ORM SQL injection-ისგან?

იმ მოთხოვნებისთვის, რომლებსაც თვითონ აგებს - დიახ. რისკი არის raw query მეთოდი, რომელსაც ყველა ORM გთავაზობს, და ის ადგილები, სადაც იდენტიფიკატორი ან clause სტრიქონად აიწყო, რადგან query builder-მა ის ვერ გამოხატა. ეს ხაზებია გადასახედი, და ისინი ჩვეულებრივ ისაა, რომლებზეც კომენტარი ბოდიშს იხდის.

რა სიხშირით უნდა შეიცვალოს ბაზის პაროლები?

გრაფიკით შეცვლა ძირითადად თეატრია. მოვლენის შემთხვევაში კი აუცილებელია: ვინმე მიდის, ავტორიზაციის მონაცემი ლოგში ან screenshot-ში გამოჩნდა, მანქანა, რომელსაც ის ჰქონდა, გატეხეს, ან მესამე მხარის ხელსაწყოს, რომელსაც წვდომა მისცემდი, ინციდენტი დაემართა. ცვლილება ისე მოაწყვე, რომ ხუთ წუთს იღებდეს და deploy არ სჭირდებოდეს, და გააკეთებ მაშინ, როცა მნიშვნელოვანია.

რა არის ამ სიაში ერთადერთი ყველაზე ღირებული რამ?

ხელმისაწვდომობის შეზღუდვა, შემდეგ კი შემოწმებული backup. პირველი თავიდან გვარიდებს იმას, რაც ხშირად ხდება; მეორე ნიშნავს, რომ დანარჩენს გადაურჩები. ყველაფერი დანარჩენი ამ ორს შორის ზიანს ავიწროვებს.

ჩემი ჰოსტი ბაზას მართავს. ამისგან რა რჩება ჩემი?

ხელმისაწვდომობა, ძრავის patch-ები და ქვედა მანქანა ჰოსტისაა. ვისაც შექმნი, რა უფლებებს მისცემ, ამოწმებს თუ არა კავშირის სტრიქონი TLS-ს, პარამეტრიზებულია თუ არა მოთხოვნები, სად ინახება ავტორიზაციის მონაცემები და აღგიდგენია თუ არა ოდესმე backup - ყველაფერი შენია, და ინციდენტები სწორედ აქედან მოდის.


კომენტარები

სრულიად ანონიმურად: ანგარიშის, ელფოსტის და cookie-ის გარეშე. ინახება მხოლოდ სახელი, ტექსტი და დრო - სხვა არაფერი. ბმულების რაოდენობა ლიმიტირებულია.

0/2000