ЁЯТЙ рдзрдбрд╛ 01 тАФ Injection: data рдХрдзреАрд╣реА command рдмрдиреВ рдирдпреЗ
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 16 рдкреИрдХреА рдзрдбрд╛ 01 ┬╖ рдкреБрдвреЗ: lesson-02-xss-csp
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рд╢рд╛рд│реЗрдЪреНрдпрд╛ security office рдЪреА рдкрд╣рд┐рд▓реА рдЦрд┐рдбрдХреА: рдЕрд░реНрдЬ рдЦрд┐рдбрдХреА (forms desk). рд╣рд╛ рдзрдбрд╛ рд╢рд┐рдХрд╡рддреЛ рддреЛ рдПрдХрдЪ рдирд┐рдпрдо web security рдордзрд▓рд╛ рд╕рд░реНрд╡рд╛рдд рдЬреБрдирд╛ рдирд┐рдпрдо рдЖрд╣реЗ тАФ user рдЬреЗ рдЯрд╛рдЗрдк рдХрд░рддреЛ рддреЗ data рдЕрд╕рддреЗ, рдХрдзреАрд╣реА command рдЪрд╛ рднрд╛рдЧ рдирд╕рддреЗ. рддреБрдореНрд╣реА рдкрд╛рд╣рд╛рд▓: text рдЬреЛрдбреВрди SQL рдордзреНрдпреЗ рдмрдирд╡рд▓реЗрд▓реЗ grade lookup, рдПрдХ crafted input рдЬреНрдпрд╛рдореБрд│реЗ рддреЗ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдЪреА grade рдкрд░рдд рджреЗрддреЗ, рдЖрдгрд┐ рдПрдХрд╛ рдУрд│реАрдЪрд╛ рдЙрдкрд╛рдп: parameterised query. рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕рднрд░ рддреБрдореНрд╣реА рд╡рд╛рдкрд░рд╛рд▓ рддреНрдпрд╛ рдЦрд▒реНрдпрд╛ files:
- sec/web.py тАФ рдЕрд░реНрдЬ рдЦрд┐рдбрдХреА: injection, XSS рдЖрдгрд┐ CSP, cookies, CSRF, CORS рдЖрдгрд┐ SSRF (рдзрдбреЗ 01тАУ03)
- sec/identity.py тАФ рдУрд│рдЦрдкрддреНрд░ рдЦрд┐рдбрдХреА: passwords, tokens, PKCE рдЖрдгрд┐ authorization (рдзрдбреЗ 04тАУ06)
- sec/cloud.py тАФ рдЗрдорд╛рд░рдд рдЦрд┐рдбрдХреА рдЖрдгрд┐ рдкрд░рд┐рд╕рд░рд╛рдЪреЗ рджрд░рд╡рд╛рдЬреЗ: KMS, secrets, IAM, networks, TLS рдЖрдгрд┐ Kubernetes (рдзрдбреЗ 07тАУ12)
- sec/supply.py тАФ delivery рдЦрд┐рдбрдХреА рдЖрдгрд┐ рд╕рд╣рд╛рдпреНрдпрдХрд╛рдЪреА рдирд┐рдпрдорд╛рд╡рд▓реА (рдзрдбреЗ 13тАУ16)
- sec/demo.py тАФ рдкреНрд░рддреНрдпреЗрдХ рдзрдбрд╛ рдПрдХ рдЫреЛрдЯрд╛ program рдореНрд╣рдгреВрди (
python3 sec/demo.py <section>; sections:injection xss browser passwords oauth authz secrets boundaries tls k8s_rbac k8s_network admission dependencies artifacts pipeline ai) - sec/test_sec.py тАФ office рдЪреНрдпрд╛ рдирд┐рдпрдорд╛рдВрд╡рд░рдЪреНрдпрд╛ 16 рддрдкрд╛рд╕рдгреНрдпрд╛
- demo-output.txt тАФ рдирд┐рд░реЛрдЧреА run рдХрд╛рдп print рдХрд░рддреЛ
ЁЯЫбя╕П рдмрдЪрд╛рд╡рд╛рддреНрдордХ рдЖрдгрд┐ рд╢реИрдХреНрд╖рдгрд┐рдХ. рдпрд╛ рдХреЛрд░реНрд╕рдордзрд▓реА рдкреНрд░рддреНрдпреЗрдХ рдХрдордХреБрд╡рдд рдЬрд╛рдЧрд╛ рдпрд╛ repo рдордзрд▓реНрдпрд╛рдЪ local, in-memory data рд╡рд░ рджрд╛рдЦрд╡рд▓реА рдЖрд╣реЗ тАФ memory рдордзрд▓реА рдПрдХ SQLite table рдЖрдгрд┐ рд╕рд╛рдзреНрдпрд╛ strings. рдХрд╛рд╣реАрд╣реА network рд▓рд╛ рдХрд┐рдВрд╡рд╛ рдЦрд▒реНрдпрд╛ system рд▓рд╛ рд╕реНрдкрд░реНрд╢ рдХрд░рдд рдирд╛рд╣реА. рдЬреЗ рд╢рд┐рдХрд╛рд▓ рддреЗ рддреБрдордЪреНрдпрд╛ рдорд╛рд▓рдХреАрдЪреНрдпрд╛ рдХрд┐рдВрд╡рд╛ рдЬреНрдпрд╛рд╡рд░ рдХрд╛рдо рдХрд░рдгреНрдпрд╛рдЪреА рдкрд░рд╡рд╛рдирдЧреА рдЖрд╣реЗ рдЕрд╢рд╛ systems рдЪреЗ рд╕рдВрд░рдХреНрд╖рдг рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рд╡рд╛рдкрд░рд╛. рддреБрдордЪреНрдпрд╛ рдорд╛рд▓рдХреАрдЪреА рдирд╕рд▓реЗрд▓реА system test рдХрд░рдгреЗ рдмрд╣реБрддреЗрдХ рджреЗрд╢рд╛рдВрдд рдХрд╛рдпрджреНрдпрд╛рд╡рд┐рд░реБрджреНрдз рдЖрд╣реЗ.
ЁЯОТ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рдЖрдзреА: рддреБрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд Python 3 рд▓рд╛рдЧрддреЗ, рджреБрд╕рд░реЗ рдХрд╛рд╣реА рдирд╛рд╣реА тАФ
pip installрдирд╛рд╣реА, cloud account рдирд╛рд╣реА. рдЦрд▒реНрдпрд╛ account рд╡рд░ рдЕрд╕реЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реНрдпрд╛ commands рд╕рд╛рдареА рддреБрдордЪрд╛ рд╕реНрд╡рддрдГрдЪрд╛ рдЦрд░рд╛ database, framework рдХрд┐рдВрд╡рд╛ cloud account рд▓рд╛рдЧрддреЛ.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рд╢рд╛рд│реЗрдЪреНрдпрд╛ office рдордзреНрдпреЗ рдПрдХ рдХрд╛рд░рдХреВрди рдЖрд╣реЗ рдЬреЛ records room рдордзреВрди grades рдЖрдгреВрди рджреЗрддреЛ. рддреБрдореНрд╣реА рдПрдХ рдЪрд┐рдареНрдареА рднрд░рддрд╛, рдЖрдгрд┐ рдХрд╛рд░рдХреВрди рддреА рдЪрд┐рдареНрдареА records room рд▓рд╛ рдореЛрдареНрдпрд╛рдиреЗ рд╡рд╛рдЪреВрди рджрд╛рдЦрд╡рддреЛ:
"рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА katrina рдЪреА grade рдЖрдгрд╛."
рдЖрддрд╛ рдПрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдирд╛рд╡рд╛рдЪреНрдпрд╛ рдЪреМрдХрдЯреАрдд рд╣реЗ рд▓рд┐рд╣рд┐рддреЛ:
katrina тАФ рдЖрдгрд┐ рдмрд╛рдХреА рд╕рдЧрд│реНрдпрд╛рдВрдЪреНрдпрд╛ grades рдкрдг рдЖрдгрд╛
рдХрд╛рд░рдХреВрди рдкреВрд░реНрдг рдЪрд┐рдареНрдареА рдореЛрдареНрдпрд╛рдиреЗ рд╡рд╛рдЪрддреЛ. Records room рд▓рд╛ рдПрдХрдЪ рд▓рд╛рдВрдмрд▓рдЪрдХ рдЖрджреЗрд╢ рдРрдХреВ рдпреЗрддреЛ, рдЖрдгрд┐ рддреА рддреЛ рдкреВрд░реНрдгрдкрдгреЗ рдкрд╛рд│рддреЗ. рдкреНрд░рддреНрдпреЗрдХ grade рдЦреЛрд▓реАрдмрд╛рд╣реЗрд░ рдЬрд╛рддреЗ.
Security office рдЪрд┐рдареНрдареА рджреБрд░реБрд╕реНрдд рдХрд░рддреЗ. рдЖрддрд╛ рдкреНрд░рд╢реНрди рдЪрд┐рдареНрдареАрд╡рд░ рдЫрд╛рдкрд▓реЗрд▓рд╛ рдЕрд╕рддреЛ: "рдпрд╛ рдЪреМрдХрдЯреАрдд рдирд╛рд╡ рд▓рд┐рд╣рд┐рд▓реЗрд▓реНрдпрд╛ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдЪреА grade рдЖрдгрд╛." рдЪреМрдХрдЯ рдлрдХреНрдд рдЪреМрдХрдЯ рдЕрд╕рддреЗ. рддрд┐рдереЗ рдЬреЗ рдХрд╛рд╣реА рд▓рд┐рд╣рд┐рд▓реЗ рдЕрд╕реЗрд▓ тАФ рдЕрдЧрджреА "рдЖрдгрд┐ рдмрд╛рдХреА рд╕рдЧрд│реНрдпрд╛рдВрдЪреНрдпрд╛ grades рдкрдг рдЖрдгрд╛" тАФ рддреЗ рдПрдХ рдирд╛рд╡ рдореНрд╣рдгреВрдирдЪ рд╡рд╛рдЪрд▓реЗ рдЬрд╛рддреЗ. рддреНрдпрд╛ рдирд╛рд╡рд╛рдЪрд╛ рдХреЛрдгрддрд╛рд╣реА рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдирд╛рд╣реА, рдореНрд╣рдгреВрди рдХрд╛рд╣реАрдЪ рдкрд░рдд рдпреЗрдд рдирд╛рд╣реА.
рддреА рдЫрд╛рдкрд▓реЗрд▓реА рдЪрд┐рдареНрдареА рдореНрд╣рдгрдЬреЗ parameterised query. рдкреНрд░рд╢реНрди рдЖрдгрд┐ рдЙрддреНрддрд░рд╛рдЪреА рдЪреМрдХрдЯ рд╡реЗрдЧрд╡реЗрдЧрд│реЗ рдкреНрд░рд╡рд╛рд╕ рдХрд░рддрд╛рдд, рддреНрдпрд╛рдореБрд│реЗ рдЪреМрдХрдЯ рдкреНрд░рд╢реНрди рдХрдзреАрдЪ рдмрджрд▓реВ рд╢рдХрдд рдирд╛рд╣реА.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
u["ЁЯзТ input<br/>x' OR '1'='1"]
subgraph bad["тЭМ glued into the text"]
s1["SELECT тАж WHERE pupil = 'x' OR '1'='1'"]
r1["3 rows тАФ every pupil"]
s1 --> r1
end
subgraph good["тЬЕ sent as a parameter"]
s2["SELECT тАж WHERE pupil = ?"]
v2["value: x' OR '1'='1"]
r2["0 rows тАФ no pupil has that name"]
s2 --> r2
v2 --> r2
end
u --> s1
u --> v2
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/security/lesson-diagrams.html#l01
тЭУ рдХрд╛рдп
- Injection тАФ user рдЪрд╛ input рдПрдЦрд╛рджреНрдпрд╛ command рдордзреНрдпреЗ (SQL, shell command, LDAP filter, template) рдорд┐рд╕рд│рд▓рд╛ рдЬрд╛рддреЛ рдЖрдгрд┐ command рдХрд╛рдп рдХрд░рддреЗ рддреЗ рдмрджрд▓рддреЛ. OWASP Top 10 (2021) рдордзреНрдпреЗ рд╣реЗ A03:2021 тАУ Injection рдЖрд╣реЗ.
- SQL injection тАФ рд╕рд░реНрд╡рд╛рдд рдкреНрд░рд╕рд┐рджреНрдз рдЙрджрд╛рд╣рд░рдг.
unsafe_lookup()f"тАж WHERE pupil = '{pupil}'"рдмрдирд╡рддреЗ.x' OR '1'='1рд╣рд╛ input quote рдмрдВрдж рдХрд░рддреЛ рдЖрдгрд┐ рдиреЗрд╣рдореА рдЦрд░реА рдЕрд╕рдгрд╛рд░реА рдПрдХ рдЕрдЯ рдЬреЛрдбрддреЛ. - Parameterised query (prepared statement) тАФ SQL text рдордзреНрдпреЗ рдПрдХ placeholder (
?,%s,$1,:name) рдЕрд╕рддреЛ рдЖрдгрд┐ value рд╡реЗрдЧрд│реА рдкрд╛рдард╡рд▓реА рдЬрд╛рддреЗ. Database рдЖрдзреА SQL parse рдХрд░рддреЛ; value рдХрдзреАрдЪ SQL рдмрдиреВ рд╢рдХрдд рдирд╛рд╣реА.safe_lookup()рд╣реЗрдЪ рдХрд░рддреЗ. - ORM тАФ рдПрдХ library (SQLAlchemy, Django ORM, Hibernate, Prisma) рдЬреА рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА parameterised queries рдмрдирд╡рддреЗ. Default рдиреЗ рд╕реБрд░рдХреНрд╖рд┐рдд тАФ рдЬреЛрдкрд░реНрдпрдВрдд рдХреЛрдгреА рддрд┐рдЪреНрдпрд╛ рдЖрдд string formatting рдиреЗ raw SQL рд▓рд┐рд╣реАрдд рдирд╛рд╣реА.
- рд╕рдЧрд│реАрдХрдбреЗ рд╣рд╛рдЪ рдирд┐рдпрдо тАФ shell: arguments рдЪреА list рджреНрдпрд╛, shell рдирдХреЛ. Templates: user рдЪреНрдпрд╛ text рдкрд╛рд╕реВрди рдХрдзреАрд╣реА template рдмрдирд╡реВ рдирдХрд╛. LDAP, XPath, NoSQL filters: library рдЪреЗ parameter рдХрд┐рдВрд╡рд╛ escaping function рд╡рд╛рдкрд░рд╛.
- рдЬреЗ parameters рдмрдиреВ рд╢рдХрдд рдирд╛рд╣реАрдд рддреНрдпрд╛ рднрд╛рдЧрд╛рдВрд╕рд╛рдареА allow-lists тАФ column рдЪреЗ рдирд╛рд╡ рдХрд┐рдВрд╡рд╛ sort order
?рдмрдиреВ рд╢рдХрдд рдирд╛рд╣реА. User рдЪреА рдирд┐рд╡рдб рдПрдХрд╛ рдард░рд▓реЗрд▓реНрдпрд╛ list рд╢реА рдЬреЛрдбрд╛:{"name": "pupil", "grade": "grade"}.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдЪреБрдХреАрдЪреНрдпрд╛ рдкрджреНрдзрддреАрдиреЗ рдмрдирд╡рд▓реЗрд▓реЗ рдПрдХ lookup рдкреВрд░реНрдг table рд╡рд╛рдЯреВрди рдЯрд╛рдХреВ рд╢рдХрддреЗ: grades, emails, password hashes. Injection рд▓рд╛ рдЦрд╛рд╕ tools рд▓рд╛рдЧрдд рдирд╛рд╣реАрдд тАФ рдлрдХреНрдд рдПрдХ text box. рдЖрдгрд┐ рдЙрдкрд╛рдп рд╕реНрд╡рд╕реНрдд рдЖрд╣реЗ: рддреАрдЪ code рдЪреА рдУрд│, placeholder рд╕рд╣ рд▓рд┐рд╣рд┐рд▓реЗрд▓реА. рд╣рд╛рддрд╛рдиреЗ quotes escape рдХрд░рдгреЗ рд╣рд╛ рдЙрдкрд╛рдп рдирд╛рд╣реА. рд╣рд╛рддрд╛рдиреЗ рдХреЗрд▓реЗрд▓реНрдпрд╛ escaping рд▓рд╛ рдЪреБрдХрд╡рдгреНрдпрд╛рдЪреЗ рдЕрдиреЗрдХ рдорд╛рд░реНрдЧ рдЖрд╣реЗрдд (рджреБрд╕рд░реА quote рдЪрд┐рдиреНрд╣реЗ, encodings, quotes рдирд╕рд▓реЗрд▓реЗ numbers). Parameter рд╣реА рд╕рдорд╕реНрдпрд╛ рдореБрд│рд╛рдкрд╛рд╕реВрди рдХрд╛рдвреВрди рдЯрд╛рдХрддреЛ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
sec/web.py рдордзрд▓реЗ grades_db() рддреАрди рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдВрд╕рд╣ рдПрдХ in-memory SQLite table
рдмрдирд╡рддреЗ: Katrina (A+), Dipika (B+) рдЖрдгрд┐ Aishwarya (A). unsafe_lookup(db, pupil) input
SQL text рдордзреНрдпреЗ рдЬреЛрдбрддреЗ. safe_lookup(db, pupil) рддреЛ parameter рдореНрд╣рдгреВрди рдкрд╛рдард╡рддреЗ:
db.execute("тАж WHERE pupil = ?", (pupil,)). sec/demo.py рдордзрд▓реЗ
injection() рджреЛрдиреНрд╣реАрдВрдирд╛ рд╕рд╛рдзреНрдпрд╛ рдирд╛рд╡рд╛рдиреЗ рдЖрдгрд┐ crafted input рдиреЗ call рдХрд░рддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 sec/demo.py injection
python3 - <<'EOF'
import sys; sys.path.insert(0, "sec"); from web import grades_db, unsafe_lookup, safe_lookup
db = grades_db()
for text in ("dipika", "x' OR '1'='1", "nobody' OR pupil LIKE '%a%", "katrina'--"):
print(f"{text!r:<30} unsafe тЖТ {len(unsafe_lookup(db, text))} rows ┬╖ safe тЖТ {len(safe_lookup(db, text))} rows")
EOF
python3 sec/test_sec.py
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
injection рд╣реЗ print рдХрд░рддреЗ:
тФАтФА the grade lookup asks for one pupil's grade
normal input 'katrina' unsafe тЖТ [('katrina', 'A+')] ┬╖ safe тЖТ [('katrina', 'A+')]
crafted input "x' OR '1'='1" unsafe тЖТ [('katrina', 'A+'), ('dipika', 'B+'), ('aishwarya', 'A')]
safe тЖТ []
the fix is the same everywhere: send data as parameters, never glue it into the command (SQL, shell, LDAP, templates)
рддреБрдордЪрд╛ snippet рд╣реЗ print рдХрд░рддреЛ:
'dipika' unsafe тЖТ 1 rows ┬╖ safe тЖТ 1 rows
"x' OR '1'='1" unsafe тЖТ 3 rows ┬╖ safe тЖТ 0 rows
"nobody' OR pupil LIKE '%a%" unsafe тЖТ 3 rows ┬╖ safe тЖТ 0 rows
"katrina'--" unsafe тЖТ 1 rows ┬╖ safe тЖТ 0 rows
Tests 16/16 passed рдиреЗ рд╕рдВрдкрддрд╛рдд.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рд╕рд╛рдзреНрдпрд╛ input рдиреЗ рджреЛрдиреНрд╣реА lookups рд╕рд╛рд░рдЦреЗрдЪ рджрд┐рд╕рддрд╛рдд тАФ рдореНрд╣рдгреВрдирдЪ рд╣рд╛ bug code review
рдЖрдгрд┐ tests рдордзреВрди рдЯрд┐рдХрддреЛ. Crafted input рдиреЗ рдЬреЛрдбрд▓реЗрд▓реА query рддрд┐рдиреНрд╣реА рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдкрд░рдд рджреЗрддреЗ, рдЖрдгрд┐
katrina'-- рддрд░ query рдЪрд╛ рдЙрд░рд▓реЗрд▓рд╛ рднрд╛рдЧ comment рдордзреНрдпреЗ рдмрджрд▓рддреЛ. Parameterised query рдкреНрд░рддреНрдпреЗрдХ crafted
input рд╕рд╛рдареА рдХрд╛рд╣реАрдЪ рдкрд░рдд рджреЗрдд рдирд╛рд╣реА: input рдиреЗрд╣рдореА рдлрдХреНрдд рдПрдХ рдирд╛рд╡рдЪ рд╣реЛрддрд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- "рдЖрдореНрд╣реА quotes escape рдХрд░рддреЛ" тАФ parameters рдРрд╡рдЬреА рд╣рд╛рддрд╛рдиреЗ рдХреЗрд▓реЗрд▓реЗ escaping
- рд╕рдЧрд│реАрдХрдбреЗ рд╕реБрд░рдХреНрд╖рд┐рдд ORM, рдЖрдгрд┐ f-string рдиреЗ рдмрдирд╡рд▓реЗрд▓рд╛ рдПрдХрдЪ
raw()рдХрд┐рдВрд╡рд╛text()call - values parameterise рдХрд░рдгреЗ рдкрдг URL рдордзреВрди column рдЪреЗ рдирд╛рд╡ рдХрд┐рдВрд╡рд╛
ORDER BYрдЬреЛрдбрдгреЗ (allow-list рд╡рд╛рдкрд░рд╛) subprocess.run(f"convert {name}.png тАж", shell=True)тАФ shell injection рд╣рд╛рдЪ bug рдЖрд╣реЗ- input "рдЖрдкрд▓реНрдпрд╛рдЪ" front end рдХрдбреВрди рдпреЗрддреЛ рдореНрд╣рдгреВрди рддреНрдпрд╛рд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рдгреЗ тАФ рдХреЛрдгреАрд╣реА рдХреЛрдгрддреАрд╣реА request рдкрд╛рдард╡реВ рд╢рдХрддреЛ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рднреЗрдЯрдгрд╛рд▒реНрдпрд╛ рднрд╛рд╖рд╛рдВрдордзрд▓рд╛ рд╣рд╛рдЪ рдЙрдкрд╛рдп. PostgreSQL (psycopg)
рд╕рд╣ Python %s placeholders рд╡рд╛рдкрд░рддреЗ тАФ Python рдЪрд╛ % operator рдирд╛рд╣реА:
# тЬЕ the value travels separately; psycopg never pastes it into the SQL text
cur.execute("SELECT pupil, grade FROM grades WHERE pupil = %s", (pupil,))
pg рд╕рд╣ Node.js рдХреНрд░рдорд╛рдВрдХрд┐рдд placeholders рд╡рд╛рдкрд░рддреЗ:
const { rows } = await pool.query(
'SELECT pupil, grade FROM grades WHERE pupil = $1', [pupil]);
JDBC рд╕рд╣ Java PreparedStatement рд╡рд╛рдкрд░рддреЗ:
try (PreparedStatement ps = conn.prepareStatement(
"SELECT pupil, grade FROM grades WHERE pupil = ?")) {
ps.setString(1, pupil);
try (ResultSet rs = ps.executeQuery()) { /* тАж */ }
}
ORM (SQLAlchemy 2.x) рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА parameter рдмрдирд╡рддреЛ тАФ рдЖрдгрд┐ raw SQL рд▓рд╛рдЧрд▓реЗ рддрд░ рддреЗ bind рдХрд░рд╛:
from sqlalchemy import select, text
rows = session.execute(select(Grade).where(Grade.pupil == pupil)).scalars().all()
rows = session.execute(text("SELECT grade FROM grades WHERE pupil = :p"), {"p": pupil}).all()
User рдЬреНрдпрд╛ column рдиреЗ sort рдХрд░реВ рд╢рдХрддреЛ рддреЛ parameter рдмрдиреВ рд╢рдХрдд рдирд╛рд╣реА тАФ рддреЛ allow-list рдордзреВрди рдЬреЛрдбрд╛:
SORTABLE = {"name": "pupil", "grade": "grade"}
column = SORTABLE.get(request.args.get("sort"), "pupil") # never the raw input
рдЖрдгрд┐ рдпрд╛рдЪ рдирд┐рдпрдорд╛рдЪреА shell рдЖрд╡реГрддреНрддреА тАФ arguments рдЪреА list, shell рдирд╛рд╣реА:
subprocess.run(["convert", f"{safe_name}.png", "out.jpg"], check=True) # no shell=True
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рддреБрдордЪреНрдпрд╛ code рдордзреНрдпреЗ
+,f",.format(рдХрд┐рдВрд╡рд╛ template strings рдиреЗ рдмрдирд╡рд▓реЗрд▓реЗ SQL, рдЖрдгрд┐shell=Trueрд╢реЛрдзрд╛. Bandit (Python) рдЖрдгрд┐ Semgrep rules рд╕рд╛рд░рдЦреЗ linters рддреНрдпрд╛рддрд▓реЗ рдмрд╣реБрддреЗрдХ рд╢реЛрдзрддрд╛рдд. App рдЪреНрдпрд╛ database user рд▓рд╛ рдлрдХреНрдд рд▓рд╛рдЧрдгрд╛рд░реЗрдЪ рдЕрдзрд┐рдХрд╛рд░ рджреНрдпрд╛, рдореНрд╣рдгрдЬреЗ рд╕реБрдЯрд▓реЗрд▓рд╛ bug рдХрдореА рд╡рд╛рдЪреВ рд╢рдХреЗрд▓.
тПня╕П рдкреБрдвреЗ
Injection рд╡рд╛рдИрдЯ input server рдЪреНрдпрд╛ commands рдХрдбреЗ рдкрд╛рдард╡рддреЗ. рдкреБрдврдЪреА рдХрдордХреБрд╡рдд рдЬрд╛рдЧрд╛ рддреЛ рдЗрддрд░ рд▓реЛрдХрд╛рдВрдЪреНрдпрд╛ browsers рдХрдбреЗ рдкрд╛рдард╡рддреЗ: notice board рд╡рд░рдЪреА рдПрдХ comment рдЬреА code рдореНрд╣рдгреВрди рдЪрд╛рд▓рддреЗ.
git checkout lesson-02-xss-csp