ЁЯЫбя╕П рдзрдбрд╛ 13 тАФ Security: рдХреБрд▓реВрдкрдмрдВрдж рдиреЛрдВрджрд╡рд╣реА
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 18 рдкреИрдХреА рдзрдбрд╛ 13 ┬╖ рдорд╛рдЧреАрд▓: lesson-12-performance-ops ┬╖ рдкреБрдвреАрд▓: lesson-14-advanced-sql
рднрд╛рдЧ 3 тАФ рдЕрдзрд┐рдХ рдЦреЛрд▓рд╛рдд. рдзрдбреЗ 01тАУ12 рдиреА рд░реЗрдХреЙрд░реНрдб рд░реВрдо рдмрд╛рдВрдзрд▓реА рдЖрдгрд┐ рдЪрд╛рд▓рд╡рд▓реА. рдзрдбреЗ 13тАУ18 рд╣реЗ interviews рдЖрдгрд┐ incidents рдордзреНрдпреЗ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдЬрд╛рдгрд╛рд░реЗ рд╡рд┐рд╖рдп рдЖрд╣реЗрдд тАФ рдкреНрд░рддреНрдпреЗрдХ рддреНрдпрд╛рдЪ
school.dbрд╡рд░ рдкреНрд░рддреНрдпрдХреНрд╖ рдЪрд╛рд▓рддреЛ.
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ13, рдЖрдгрд┐ db/demo.py рдордзрд▓реЗ inject(): рдЯрд╛рдЗрдк рдХреЗрд▓реЗрд▓рд╛
roll number рдереЗрдЯ SQL рдордзреНрдпреЗ рдЪрд┐рдХрдЯрд╡рдгрд╛рд░рд╛ login, рддреЛрдЪ login parameter рд╕рд╣, рдЖрдгрд┐ DELETE
рдирд╛рдХрд╛рд░рд▓рд╛ рдЬрд╛рдгрд╛рд░реЗ read-only connection.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдЕрднрд┐рд▓реЗрдЦрдкрд╛рд▓ рддреБрдордЪреА рдЪрд┐рдареНрдареА рдореЛрдареНрдпрд╛рдиреЗ рд╡рд╛рдЪрддреЗ рдЖрдгрд┐ рддреНрдпрд╛рдд рдЬреЗ рд▓рд┐рд╣рд┐рд▓реЗ рдЖрд╣реЗ рддреЗрдЪ рдХрд░рддреЗ. рдЪрд┐рдареНрдареАрд╡рд░ "roll number 3A-02 рд╢реЛрдзрд╛" рдЕрд╕реЗрд▓, рддрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрддрд░рд┐рдирд╛ рдорд┐рд│рддреЗ. рдкрдг рдХреЛрдгреА рд░рд┐рдХрд╛рдореНрдпрд╛ рдЬрд╛рдЧреЗрдд рд╕реНрд╡рддрдГрдЪреЗ рд╢рдмреНрдж рд▓рд┐рд╣рд┐рд▓реЗ рддрд░ тАФ "roll number x' OR '1'='1 рд╢реЛрдзрд╛"? рдореЛрдареНрдпрд╛рдиреЗ рд╡рд╛рдЪрд▓реНрдпрд╛рд╡рд░ рдЪрд┐рдареНрдареА рдЖрддрд╛ рдореНрд╣рдгрддреЗ "roll number x рд╢реЛрдзрд╛, рдХрд┐рдВрд╡рд╛ рдЬрд┐рдереЗ 1 рдмрд░реЛрдмрд░ 1 рдЖрд╣реЗ рддреЗ рд╕рдЧрд│реЗ" тАФ рдЖрдгрд┐ 1 рдиреЗрд╣рдореАрдЪ 1 рдмрд░реЛрдмрд░ рдЕрд╕рддреЛ. рдЕрднрд┐рд▓реЗрдЦрдкрд╛рд▓ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рджреЗрдКрди рдЯрд╛рдХрддреЗ. рд╣реЗрдЪ SQL injection.
рдЙрдкрд╛рдп рдореНрд╣рдгрдЬреЗ рд░рд┐рдХрд╛рдореНрдпрд╛ рдЬрд╛рдЧреА рдмрдВрдж рд▓рд┐рдлрд╛рдлрд╛ (?) рдЕрд╕рд▓реЗрд▓реА рдЪрд┐рдареНрдареА. рд▓рд┐рдлрд╛рдлреНрдпрд╛рдд рдЬреЗ рдЕрд╕реЗрд▓
рддреЗ рдиреЗрд╣рдореА рдлрдХреНрдд рд╢реЛрдзрд╛рдпрдЪреА рдПрдХ value рдЕрд╕рддреЗ тАФ рдЕрднрд┐рд▓реЗрдЦрдкрд╛рд▓ рдкрд╛рд│рддреЗ рдЕрд╕реЗ рд╢рдмреНрдж рдХрдзреАрдЪ рдирд╛рд╣реАрдд.
рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░рдХреБрдирд╛рд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ рдХрд┐рд▓реНрд▓реА рдорд┐рд│рдд рдирд╛рд╣реА: reports рдХрд╛рд░рдХреБрдирд╛рд▓рд╛ рдлрдХреНрдд-рд╡рд╛рдЪрдгреНрдпрд╛рдЪрд╛ pass рдорд┐рд│рддреЛ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
typed["тМия╕П typed: x' OR '1'='1"]
glued["тЭМ glued: WHERE roll_no = 'x' OR '1'='1'"]
param["тЬЕ parameter: WHERE roll_no = ? + value"]
leak["ЁЯТе all 5 pupils"]
none["(no rows)"]
typed --> glued --> leak
typed --> param --> none
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/database/lesson-diagrams.html#l13
тЭУ рдХрд╛рдп
- SQL injection тАФ user рдЪреЗ input SQL text рдЪрд╛ рднрд╛рдЧ рдмрдирддреЗ, рддреНрдпрд╛рдореБрд│реЗ input
рдкреНрд░рд╢реНрдирдЪ рдмрджрд▓реВ рд╢рдХрддреЗ. рддреЗ рд╕рдЧрд│реЗ рд╡рд╛рдЪреВ рд╢рдХрддреЗ, login рдЯрд╛рд│реВ рд╢рдХрддреЗ, рдХрд┐рдВрд╡рд╛ (рдЗрддрд░ drivers рд╕рд╣)
DROP TABLEрдЪрд╛рд▓рд╡реВ рд╢рдХрддреЗ. - Parameters (
?,%s,:name,$1) тАФ SQL рдЖрдгрд┐ values рд╡реЗрдЧрд╡реЗрдЧрд│реЗ рдЬрд╛рддрд╛рдд; value рдХрдзреАрдЪ SQL рдореНрд╣рдгреВрди parse рд╣реЛрдд рдирд╛рд╣реА. рдкреНрд░рддреНрдпреЗрдХ driver рдЖрдгрд┐ ORM рдордзреНрдпреЗ рддреЗ рдЕрд╕рддрд╛рдд. - Least privilege тАФ рдкреНрд░рддреНрдпреЗрдХ app рдлрдХреНрдд рдЧрд░рдЬреЗрдЪреЗ рддреЗрд╡рдвреЗрдЪ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ role рдореНрд╣рдгреВрди connect рд╣реЛрддреЗ:
GRANT SELECT ON grades TO reports;(Postgres/MySQL). SQLite рдордзреНрдпреЗ users рдирд╛рд╣реАрдд; рд╕рд░реНрд╡рд╛рдд рдЬрд╡рд│рдЪреА рдЧреЛрд╖реНрдЯ рдореНрд╣рдгрдЬреЗ file read-only рдЙрдШрдбрдгреЗ (mode=ro). - Encryption тАФ transit рдордзреНрдпреЗ (TLS: Postgres рдордзреНрдпреЗ
sslmode=require) рдЖрдгрд┐ at rest (disk рдХрд┐рдВрд╡рд╛ managed service, рдЙрджрд╛. RDS). Passwords secret store рдХрд┐рдВрд╡рд╛ environment рдордзреВрди рдпреЗрддрд╛рдд, рдХрдзреАрдЪ git рдордзреВрди рдирд╛рд╣реА.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдЬреЛ connect рдЭрд╛рд▓рд╛ рдЖрд╣реЗ рддреНрдпрд╛рдЪреНрдпрд╛рд╡рд░ database рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рддреЛ. рджреЛрди рджрд╢рдХрд╛рдВрдкрд╛рд╕реВрди injection рд╣рд╛ рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдорд╛рдиреНрдп web рд╣рд▓реНрд▓реНрдпрд╛рдВрдкреИрдХреА рдПрдХ рдЖрд╣реЗ, рдЖрдгрд┐ рддреЛ рдПрдХрд╛ рд╕рд╡рдпреАрдиреЗ рдкреВрд░реНрдгрдкрдгреЗ рдерд╛рдВрдмрддреЛ: strings рдЪрд┐рдХрдЯрд╡реВрди рдХрдзреАрдЪ SQL рдмрдирд╡реВ рдирдХрд╛. Least privilege рдЗрддрд░ рдкреНрд░рддреНрдпреЗрдХ рдЪреБрдХреАрдЪреЗ рдиреБрдХрд╕рд╛рди рдорд░реНрдпрд╛рджрд┐рдд рдареЗрд╡рддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
db/demo.py рдордзрд▓реЗ inject() database рд▓рд╛ рдкреНрд░рддреНрдпрдХреНрд╖ рдорд┐рд│рд╛рд▓реЗрд▓реА рдЪрд┐рдХрдЯрд╡рд▓реЗрд▓реА query
рдЫрд╛рдкрддреЗ, рддреА рдЪрд╛рд▓рд╡рддреЗ (рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдкрд░рдд рдпреЗрддреЗ), parameter рдЕрд╕рд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА рдЪрд╛рд▓рд╡рддреЗ (рдПрдХрд╣реА row рдирд╛рд╣реА),
рдордЧ school.db read-only рдЙрдШрдбреВрди DELETE FROM grades рдХрд░реВрди рдкрд╛рд╣рддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 db/demo.py inject
python3 - <<'EOF'
import sqlite3
c = sqlite3.connect("db/school.db")
for typed in ["3A-02", "x' OR '1'='1", "3A-02'; --"]:
print(repr(typed), "тЖТ", c.execute("SELECT name FROM students WHERE roll_no = ?", (typed,)).fetchall())
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
рдЪрд┐рдХрдЯрд╡рд▓реЗрд▓реА query WHERE roll_no = 'x' OR '1'='1' рдЫрд╛рдкрддреЗ рдЖрдгрд┐ рдкрд╛рдЪрд╣реА рдирд╛рд╡реЗ рдкрд░рдд рджреЗрддреЗ;
parameter (no rows) рджреЗрддреЛ; read-only connection attempt to write a readonly database рдореНрд╣рдгрддреЗ. Snippet рдордзреНрдпреЗ рдлрдХреНрдд 3A-02 рд▓рд╛ рдХрддрд░рд┐рдирд╛ рд╕рд╛рдкрдбрддреЗ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рддреБрдореНрд╣реА injection рдЪрд╛рд▓рддрд╛рдирд╛ рджрд╛рдЦрд╡реВ рд╢рдХрддрд╛, рддреЗ рдХрд╛ рд╣реЛрддреЗ рд╣реЗ рд╕рдордЬрд╛рд╡реВ рд╢рдХрддрд╛, рдЖрдгрд┐ parameter рдиреЗ рддреЗ рдмрдВрдж рдХрд░реВ рд╢рдХрддрд╛ тАФ рдЖрдгрд┐ app рд▓рд╛ рдЕрд╕рд╛ pass рджреЗрдК рд╢рдХрддрд╛ рдЬреЛ рдХрд╛рд╣реАрдЪ рд▓рд┐рд╣реВ рд╢рдХрдд рдирд╛рд╣реА.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- parameters рд╡рд╛рдкрд░рдгреНрдпрд╛рдРрд╡рдЬреА quotes рд╣рд╛рддрд╛рдиреЗ escape рдХрд░рдгреЗ
- "рдлрдХреНрдд рдпрд╛ рдПрдХрд╛ internal tool рд╕рд╛рдареА" SQL рдмрдирд╡рд╛рдпрд▓рд╛ f-strings рдХрд┐рдВрд╡рд╛
+ - user input рдордзреВрди table рдХрд┐рдВрд╡рд╛ column рдЪреА рдирд╛рд╡реЗ тАФ parameters рдордзреНрдпреЗ рдирд╛рд╡реЗ рдмрд╕рдд рдирд╛рд╣реАрдд; allow-list рд╡рд╛рдкрд░рд╛
- app database owner рдХрд┐рдВрд╡рд╛ superuser рдореНрд╣рдгреВрди connect рд╣реЛрдгреЗ
- repo рдордзреНрдпреЗ, logs рдордзреНрдпреЗ, рдХрд┐рдВрд╡рд╛ git рдордзреНрдпреЗ commit рдХреЗрд▓реЗрд▓реНрдпрд╛ connection string рдордзреНрдпреЗ passwords
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: security reviews рдиреЗрдордХреЗ рд╣реЗрдЪ рддрдкрд╛рд╕рддрд╛рдд: string рдиреЗ рдмрдирд╡рд▓реЗрд▓рд╛ SQL рдирд╛рд╣реА, app / migrations / reports рд╕рд╛рдареА рд╡реЗрдЧрд│реЗ roles, TLS рдЖрд╡рд╢реНрдпрдХ, at rest encryption, vault рдордзреВрди secrets, рдЖрдгрд┐ superuser рдЪреНрдпрд╛ logins рд╡рд░ alert.
тПня╕П рдкреБрдвреЗ
git checkout lesson-14-advanced-sql тАФ рдПрдХрд╣реА row рди рдЧрдорд╛рд╡рддрд╛ rankings рдЖрдгрд┐ reports.