最後更新: 2024-01-31
目錄
- HTTP Method
- Cookie
- Frame Settings
- HSTS
- CSP
- X-Content-Type-Options
- CORS (Origin Header)
- Referer Header
- Apache Security Settings
-
Nginx Summary
- CORS
HTTP Method
/etc/httpd/conf/httpd.conf
TraceEnable Off
Cookie
常見問題: Session cookie(PHPSESSID)
- Cookie No HttpOnly Flag
- Cookie without SameSite Attribute
- Cookie Without Secure Flag
Syntax
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly; Secure; SameSite=Strict
說明
HttpOnly Flag
Forbids JavaScript from accessing the cookie.
Note that a cookie that has been created with HttpOnly will still be sent with JavaScript-initiated requests.
(XMLHttpRequest.send() or fetch()) # This mitigates attacks against cross-site scripting (XSS).
Secure Flag
To ensure that the cookie is encrypted (HTTPS)
SameSite Flag
Controls whether or not a cookie is sent with cross-site requests
- Strict # only for same-site requests
-
Lax(default) # Means that the cookie is not sent on cross-site requests,
# such as on requests to load images or frames,
# but is sent when a user is navigating to the origin site from an external site
# (for example, when following a link) - None # both cross-site and same-site requests
PHP
php.ini
[Session] session.cookie_secure = 1 session.cookie_httponly = 1 session.cookie_samesite = "Strict" # PHP 7.3 才有 cookie_samesite
.htaccess
# 舊版本的 php (Ver<7.3) 要使用 Apache 實現, 因為它沒有 php.ini 設定
* 注意原來的 "^(.*)$", 別重複設定. 比如原本已經有 "httponly; samesite=lax;"
.htaccess
Header edit Set-Cookie "^(PHPSESSID)=(.*)$" "$1=$2; SameSite=Strict"
Or
Header always edit Set-Cookie ^(.*)$ $1; Secure
Frame
add_header X-Frame-Options "SAMEORIGIN";
HSTS(RFC 6797)
HSTS = HTTP Strict Transport Security
[功能]
It against man-in-the-middle attacks
原因: prevent protocol downgrade(https -> http) attacks and cookie hijacking
It forces browsers to open websites with secure HTTPS connections only.
* unlike any other SSL error, users can’t bypass the HSTS error pages by clicking on "Proceed to x.y (unsafe)"
[運作]
A header over an HTTPS connection (HSTS headers over HTTP are ignored)
http header
- "Strict-Transport-Security"
- "Strict-Transport-Security: max-age=31536000"
i.e.
# Apache Settings. 7 days
add_header Strict-Transport-Security "max-age=604800; includeSubDomains";
[前題]
Trust on first use
If your browser has stored HSTS settings for a domain and
you later try to connect over HTTP or a broken HTTPS connection, you will receive an error.
Cleanup hsts on domain
chrome://net-internals/#hsts
Scroll down the page to the "Delete domain security policies" section.
Input domain name
"HSTS preloaded list"
此 list 的目的: The initial request remains unprotected
Which is a list that contains known sites supporting HSTS.
CSP(Content-Security-Policy)
Header Name: Content-Security-Policy
Syntax:
Content-Security-Policy: <policy-directive>; <policy-directive>
Settings
policy-directive
default-src
'default-src' is used as a fallback.
Content-Security-Policy default-src 'self' 'unsafe-eval' 'unsafe-inline' data:;
'self'
same URL scheme and port number
'unsafe-eval'
Allows the use of eval() # code from strings
'unsafe-inline'
CSP 強迫開發者必須把所有 inline 程式碼移到外部檔案. 加入 unsafe-inline 就可以 inline
data:
圖片以 base64 embed 到 HTML 內
<img src="data:image/png;base64,... />
script-src
specifies valid sources for JavaScript
script-src <source> <source>;
frame-ancestors, form-action
do not fallback to default-src, missing/excluding them is the same as allowing anything.
frame-ancestors
directive specifies valid parents that may embed a page using <frame>, <iframe>, <object>, <embed>, or <applet>.
form-action
directive restricts the URLs which can be used as the target of form submissions from a given context.
Example1:
Content-Security-Policy default-src 'self' *.example.com 'unsafe-eval' 'unsafe-inline';
*.example.com 係 http:// 及 https://, 沒有包 ws://, wss://
websocket 要另外加
wss://*.example.com OR ws://*.example.com
Example2: Apache .htaccess
<ifmodule mod_headers.c> # CSP Header set Content-Security-Policy: "default-src 'self' data:;\ script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.gstatic.com/ https://gitcdn.github.io/ https://cdnjs.cloudflare.com/;\ style-src 'self' 'unsafe-inline' https://gitcdn.github.io/ https://fonts.googleapis.com/ https://unpkg.com/;\ font-src 'self' data: https://fonts.gstatic.com/ https://unpkg.com/;\ frame-ancestors 'self';\ form-action 'self';\ img-src 'self' data:;" </ifmodule>
Example3: Apache Config
Header set Content-Security-Policy: "default-src 'self' data: 'unsafe-inline' 'unsafe-eval' 'unsafe-eval' \ https://fonts.googleapis.com/ \ https://fonts.gstatic.com/ \ https://www.google.com/recaptcha/ \ https://www.gstatic.com/recaptcha/;"
X-Content-Type-Options
helps prevent browsers from trying to sniff the MIME type
= instructs browsers to disable "Content or MIME sniffing"
MIME sniffing
In the absence of a MIME type, or in certain cases where browsers believe they are incorrect,
browsers may perform MIME sniffing — guessing the correct MIME type by looking at the bytes of the resource.
Setting
Header set X-Content-Type-Options "nosniff"
Cross-origin resource sharing (CORS)
A browser mechanism which enables controlled access to resources located outside of a given domain.
An example of a cross-origin request:
The front-end JavaScript code served from https://domain-a.com
uses XMLHttpRequest to make a request for https://domain-b.com/data.json.
For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts.
Header: Access-Control-Allow-Origin
Browser 的 Requests
一共有兩類 request
1) Simple requests
2) Browser 在 request 之前會先發送 preflight request (預檢請求),
Let the server know what X
- Access-Control-Allow-Origin
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
- Access-Control-Allow-Credentials
same-origin policy = 相同的 protocol, domain, port
Simple requests
Some requests don't trigger a CORS preflight.
One of the allowed methods: GET, HEAD, POST
Flow
Client -> Server
# HEADER Origin: https://foo.example
Client <- Server
# HEADER Access-Control-Allow-Origin: *
Example: .htaccess
- * # All
- URL #
- null # Specifies the origin "null"
# Server accessed by any origin
Header always set Access-Control-Allow-Origin *
# Allow https://mozilla.org # Apache Example
Header always set Access-Control-Allow-Origin https://mozilla.org
Other
CORS preflight
A request that doesn’t trigger a CORS preflight—a so-called “simple request”
It is one that meets all the following conditions: ...
Preflight Cache(Access-Control-Max-Age)
Set a cache for the OPTIONS check
You can set a Access-Control-Max-Age for the OPTIONS request,
so that it will not check the permission again until it is expired.
For Chrome, the maximum seconds for Access-Control-Max-Age is 600
Access-Control-Max-Age only works for one resource every time (same URL & same method)
Preflight Request Method: OPTIONS
<location /gql/>
Require all granted
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, PATCH, HEAD, DELETE"
Header always set Access-Control-Allow-Headers "Content-Type, Authorization"
Header always set Access-Control-Max-Age "600"
Header merge Vary "Origin"
# Preflight
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* $1 [R=200,L]
</location>
Notes
1)
不加 rewrite 的話, 會有 error
HTTP/1.1 405 Method Not Allowed
獲得的 Access-Control-Allow-* 會無效
2)
由於用了 Rewrite, 那會沒有了原有的 Header, 所以要用 "always" 加上
# 沒 alway 時
HTTP/1.1 200 OK Date: Mon, 13 May 2024 02:12:34 GMT Server: X-Frame-Options: SAMEORIGIN, SAMEORIGIN Strict-Transport-Security: max-age=86400; includeSubDomains X-Content-Type-Options: nosniff Permissions-Policy: fullscreen=(self), web-share=(self) Content-Length: 489 Connection: close Content-Type: text/html; charset=iso-8859-1
Testing
curl -I -X OPTIONS https://URL/gql/
Origin = Request Header
Indicates the origin (scheme, hostname, and port) that caused the request
It is used to provide the "security context" for the origin request
Syntax
- Origin: null
- Origin: <scheme>://<hostname>
- Origin: <scheme>://<hostname>:<port>
測試
# -D, --dump-header <filename>
curl -H "Origin: https://www.google.com.hk" \
-D header.txt \
https://www.google.com.hk/ > /dev/null
cat header.txt
* 要加上 Origin header 去 check, 因為 Server 有機會因應不同的 request 有無同的 result
* 要加 http / https
Settings: Apache
.htaccess
Header always set Content-Security-Policy self
Referer Header
它與 Origin 相似.
The Referer HTTP request header contains an absolute or partial address of the page that makes the request.
This data can be used for analytics, logging, optimized caching, and more.
i.e.
在沒有設定 Referrer-Policy 的情況下
當在 web page "http://example.com/pricing/" 內 clicks link ("https://www.google.com"),
Browser 就會在 Referer header send "full originating URL" ("http://example.com/pricing/")
到 Google("https://www.google.com").
Referrer-Policy
i.e.
- Referrer-Policy: no-referrer # do not include any referrer information.
- Referrer-Policy: origin # Send only the origin in the Referer header. (https://domain)
- Referrer-Policy: same-origin # Don't send the Referer header for cross-origin requests.
- Referrer-Policy: strict-origin # Don't send the Referer header to less secure destinations (HTTPS→HTTP).
- ...
.htaccess
Header always set Referrer-Policy origin
Nginx Summary
# 7 days add_header Strict-Transport-Security "max-age=604800; includeSubDomains; preload"; add_header X-Frame-Options sameorigin; add_header X-Content-Type-Options nosniff; add_header Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'"; add_header Referrer-Policy "same-origin"; add_header X-Download-Options noopen;
CORS
# 如果要在 php 自定 "", 那要保留這 header, 不能 Cleanup !
#proxy_set_header Origin '';
HTTP_ORIGIN Header
- The Origin request header indicates the origin (scheme, hostname, and port) that caused the request.
- The Origin header is similar to the Referer header, but does not disclose the path, and may be null.
Origin: null Origin: <scheme>://<hostname> Origin: <scheme>://<hostname>:<port>
php code
<? var_dump($_SERVER['HTTP_ORIGIN']); header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN'] . ""); ?>
測試
# 模擬 js 由 domainB 連到 domainA
curl -I -H "origin: https://domainB" https://domainA/
access-control-allow-origin: https://domainB