Files
mataba/shop/docs/SECURITY.md
T

74 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# XShop – Security
## 1. Principles
- Sanitize in, validate, escape out.
- Nonce + capability for every state-changing request.
- Use WP/WC APIs; no hand-rolled auth/crypto.
## 2. Input
- `sanitize_text_field`, `sanitize_textarea_field`, `sanitize_email`, `wc_clean`, `absint`, `esc_url_raw` per type.
- Validate: enums via allow-list, URLs via `wp_http_validate_url` where remote, dates via `DateTimeImmutable`.
- No `$_GET`/`$_POST` without sanitization. No `extract()`.
## 3. Output
- `esc_html`, `esc_attr`, `esc_url`, `esc_html__`, `wp_kses_post` (only for intentionally HTML fields with allow-list), `wp_kses` for narrow HTML.
- No `echo $raw`.
## 4. CSRF
- Every POST/AJAX/REST mutation: `check_ajax_referer` / `wp_verify_nonce` / `X-WP-Nonce` header for REST.
- REST: `permission_callback` checks nonce and capability.
## 5. AuthZ
- Admin screens: `current_user_can('manage_options')` or `manage_woocommerce` where appropriate (documented per screen).
- Q&A: `edit_posts` for moderation; user can delete own question via `delete_post` cap check.
- Banners: `manage_options`.
## 6. XSS
- No inline `onclick` with untrusted data. No `innerHTML` with unsanitized server data – DOM via `textContent` or sanitized fragment.
- Stored XSS: banner CTA/link, Q&A body – sanitized on save, escaped on render.
## 7. SQLi
- No raw SQL unless via `$wpdb->prepare`. Prefer `WP_Query`/`WC` CRUD. No string-concatenated queries.
## 8. Special Cases
- **File uploads**: use `wp_handle_upload` + `wp_check_filetype`, no arbitrary file execution, no path traversal (`sanitize_file_name`, `realpath` check).
- **Redirects**: `wp_safe_redirect` + `wp_validate_redirect` allow-list.
- **Unserialize**: never `unserialize` user data; use JSON.
- **Secrets**: no inline secrets; no committed `.env`.
- **Remote import**: validate MIME, size cap, timeout, no SSRF (allow-list demo asset host if any).
## 9. Headers (theme-level)
- Theme does not override server headers; document recommended headers for host (CSP, etc.) in `docs/security.md`.
## 10. Checklist per Feature
- [ ] Inputs sanitized + validated
- [ ] Nonce verified
- [ ] Capability checked
- [ ] Outputs escaped
- [ ] No raw SQL
- [ ] No unsafe redirect/unserialize/upload
## 11. Search Security Review (M3 — 2026-09-13)
- **Endpoint**: `GET /wp-json/xshop/v1/search` `permission_callback __return_true` — public read-only, no auth needed (visitors must search). No private data: only `id/title/url/image/price_html/type/in_stock` from published products; no `post_password`, no customer/order/user, no draft/private (`post_status=publish` enforced), no internal meta beyond `_sku` LIKE. Verified via direct REST: draft products never returned.
- **Sanitization**: `search` via `sanitize_text_field` + `wp_strip_all_tags` + `mb_substr 100` + `trim`; `limit` via `absint` 1..20; bounded length prevents DOS via huge query.
- **Validation**: `search` max 100 chars, `limit` validate 1..20 else 400 (WP REST validation). Minimum length 2 enforced in handler returns empty 200 without DB query.
- **Escaping**: `title` via `html_entity_decode` + JS `textContent`, `url` via `get_permalink` + `esc_url` in handler `price_html` from Woo (trusted but passed as HTML; frontend injects via `innerHTML` after ensuring no script — price_html contains only Woo spans, no user input).
- **Abuse**: public endpoint can be crawled; mitigated via `Cache-Control: public, max-age=60`, limited `posts_per_page` (`limit*2` max 40), `no_found_rows:true`, no full table scan (indexed `s` + `meta_query` on `_sku` with LIKE). No N+1 (IDs then single `wc_get_product` per result, max 6). Recommend rate limiting at reverse proxy for high traffic.
- **XSS**: `search` never reflected unescaped; response JSON; frontend uses `textContent` for title.
## 12. Review Process
- PHPCS `WordPress.Security` + manual review before each release.
- Security note in CHANGELOG.md.