Web Security & Security Header

最後更新: 2024-01-31

目錄

 


Insecure 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

Value: 'default-src' 'self' 'unsafe-inline'

  • unsafe-inline

CSP 強迫開發者必須把所有 inline 程式碼移到外部檔案

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.

Example: 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>

Example: 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-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Origin
  • 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

Header always set Access-Control-Allow-Origin https://mozilla.org

Other

multiple_domain_cors

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

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 "3600"
        Header merge Vary "Origin"
        RewriteCond %{REQUEST_METHOD} OPTIONS
        RewriteRule ^.*$ $1 [R=200,L]
    </location>

* 由於用了 Rewrite, 那會沒有了 Header, 所以自己加返 "Header always"

Testing

curl -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>

測試

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

 * -D => --dump-header <filename>

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