Skip to content
Let’s plan the right software for your processes. Call us for a demo or a quote: +90 546 737 48 29

TR EN DE

Security headers and HTTPS

Security headers are short instructions that the server sends to the browser with every response: "connect to this site only over HTTPS", "do not display this page inside other sites' frames", "run scripts only from these sources". They are added with a few lines of configuration, without changing your code, and they activate the browser's built-in protections.

Headers do not close vulnerabilities in the code; they are a second layer that limits the damage when a mistake is made. This guide first explains how to enforce HTTPS, then what each header does and how it is defined in Apache. For what SSL is, see the What is SSL? guide.

In brief

  • All traffic is redirected to HTTPS with a 301.
  • HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy are added with a few lines.
  • CSP is started in report-only mode and enforced once the violations are resolved.
  • HSTS should not be switched on for a long period before it has been tried for a short one.

Caution

The examples are for Apache 2.4 and mod_headers. Before adding the headers, try them in a test environment or at a low-traffic hour; HSTS and CSP in particular can make the site unreachable or appear broken if they are set incorrectly.

On this page

Implementation in four steps

  1. Redirect all traffic to HTTPS

    If the site's http:// address stays open after the certificate has been installed, visitors can carry on connecting without encryption. Send all requests to HTTPS with a permanent (301) redirect.

    .htaccess (Apache)
    RewriteEngine On
    
    # For requests that arrive directly at the server
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
    # If you are behind a CDN / reverse proxy, use this instead of the condition above:
    # RewriteCond %{HTTP:X-Forwarded-Proto} =http
    # RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    If your site is behind a CDN or a reverse proxy (for example Cloudflare), your server may see the request as HTTP and this rule may cause an endless redirect. In that case, set up the redirect in the CDN panel or use the X-Forwarded-Proto header in the condition.

    Flow diagram: an http request is redirected to the https address with a 301; on later visits HSTS makes the browser use https directly : Enlarge
  2. Add the basic headers

    The block below contains the headers that can safely be added to almost any site. Add it to the copy of the .htaccess file in the web root.

    .htaccess (Apache)
    <IfModule mod_headers.c>
        # In HTTPS responses only: the browser should always connect to this site over HTTPS.
        # Try it with max-age=300 first; if there are no problems, set 31536000 (1 year).
        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" "expr=%{HTTPS} == 'on'"
    
        # Do not guess the file type
        Header always set X-Content-Type-Options "nosniff"
    
        # Being displayed inside other sites' frames
        Header always set X-Frame-Options "SAMEORIGIN"
    
        # Only the domain should go to other sites
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
        # Switch off unused browser features
        Header always set Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=()"
    </IfModule>
    Diagram: security headers and what they do; HSTS, CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy : Enlarge
  3. Start CSP in report-only mode

    Content-Security-Policy is the most powerful header but also the one that needs the most care. Add it first under the name Content-Security-Policy-Report-Only: nothing is blocked, and violations appear in the browser console. Move to enforcement once you have resolved the violations.

    Flow diagram: CSP report-only mode, reviewing violations, fixing the policy, moving to enforcement : Enlarge
  4. Verify the result

    In the browser's developer tools, select the page request in the Network tab and look at the response headers, or request the headers from the command line. Check that the headers arrive not only on the home page but also on error pages and subpages.

    Command line
    # Show the response headers (with your own domain)
    curl -sI https://www.example.com/
    
    # Verify that the HTTP address redirects to HTTPS
    curl -sI http://www.example.com/ | grep -i -E "^(HTTP|location)"
    Checklist: https redirect, HSTS, nosniff, frame protection, referrer, permissions, CSP : Enlarge

Signs: how do you spot a missing header?

  • The site's http:// address opens without being redirected to HTTPS.
  • There are "mixed content" warnings in the browser console: an HTTPS page is loading an image or a script over HTTP.
  • The response headers do not include Strict-Transport-Security, X-Content-Type-Options or Content-Security-Policy.
  • Your site can be opened as a frame (iframe) inside another site.
  • In the response, the X-Powered-By header or a detailed Server header gives away version information.

The headers in detail

Strict-Transport-Security (HSTS)

Tells the browser to connect to this domain only over HTTPS for the stated period. Even if the user types the address with http://, the browser converts it to HTTPS before sending the request; this prevents the unencrypted moment in the first request from being intercepted and abused.

  • It should be sent only in HTTPS responses.
  • Try it first for a short period (for example max-age=300); if there are no problems, raise it to one year (31536000).
  • includeSubDomains covers all subdomains. Before adding it, make sure you have no subdomain that does not support HTTPS.
  • preload is for having the domain included in the browsers' built-in list and is hard to reverse; do not add it unless you are sure.

X-Content-Type-Options

The value nosniff prevents the browser from guessing the type of a file by looking at its content. For example, it stops a file uploaded as an image from being interpreted as a script. It has next to no side effects; it should be on for every site.

X-Frame-Options and frame-ancestors

Prevents your site from being displayed inside a frame on another site. This protects against the user being made to click without noticing through an invisible frame (clickjacking). SAMEORIGIN allows framing only by your own site. Its modern equivalent is the frame-ancestors directive of CSP; sending the two together covers old and new browsers.

Referrer-Policy

Determines which address information the browser passes on when a visitor moves from your site to another site. strict-origin-when-cross-origin is a balanced value: only your domain goes to other sites; the page path and parameters do not.

Permissions-Policy

Determines whether the page and the frames embedded in it may use browser features such as the camera, microphone and location. Switching off the features you do not use prevents a foreign script that has got into the page from requesting them. If your site has a map or location feature, leave the relevant permission open for your own origin.

Content-Security-Policy step by step

CSP defines which sources the page may load content from. The main directives:

  • default-src: The default source for types not specified in the other directives.
  • script-src: The sources scripts may be loaded from. This is what provides the main protection against XSS.
  • style-src, img-src, font-src, connect-src: Styles, images, fonts and background requests.
  • frame-ancestors: Who may frame the page.
  • object-src 'none' and base-uri 'self': Block legacy plugin content and tampering with the <base> tag.
  • form-action: The addresses forms may be submitted to.

A policy in report-only mode to start with:

.htaccess (Apache)
<IfModule mod_headers.c>
    Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'"
</IfModule>

Adjust the policy according to the violations in the console: add the external sources you use (fonts, analytics, maps) to the relevant directive one by one. Moving inline scripts and event attributes such as onclick into separate files lets you remove the 'unsafe-inline' value from the script-src directive; this is the real value of CSP against XSS. When the violations have stopped, switch the header to enforcement mode:

.htaccess (Apache)
<IfModule mod_headers.c>
    # Once the violations are resolved: the same policy, this time enforced
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'"
</IfModule>

For inline scripts that cannot be moved, a nonce value regenerated on every response can be used; in that case the header is sent by PHP.

PHP
<?php
// A new nonce is generated for every response
$nonce = base64_encode(random_bytes(16));
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-$nonce'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'");
?>
<script nonce="<?= htmlspecialchars($nonce, ENT_QUOTES, 'UTF-8') ?>">
    // Only inline scripts carrying this nonce value will run
    document.documentElement.classList.add('js');
</script>

Reduce version information

The PHP and server versions being visible in the response headers is not a vulnerability in itself, but it gives automated scans unnecessary information. For PHP, the expose_php = Off setting removes the X-Powered-By header. The detail in Apache's Server header is reduced with ServerTokens in the server configuration; on shared hosting this setting is in the provider's hands.

.htaccess (Apache)
<IfModule mod_headers.c>
    Header always unset X-Powered-By
    Header unset X-Powered-By
</IfModule>

# In php.ini or .user.ini:
# expose_php = Off

The real protection is not hiding the version but keeping it up to date.

Common mistakes

  • Switching HSTS on for a long period without trying it: If a certificate problem arises, visitors cannot get to the site at all; it cannot be undone until the period expires.
  • Allowing everything in CSP: A policy such as script-src * 'unsafe-inline' 'unsafe-eval' provides no protection.
  • Sending the headers only from PHP: The headers do not arrive on images, error pages and static files. Defining them in the server configuration gives wider coverage.
  • Leaving mixed content: Change your own addresses that start with http:// to https:// in templates and in the content in the database.
  • Forgetting the cookies: After moving to HTTPS, add the Secure flag to the session cookie. See Login and session security.

Checklist

  • HTTP requests are redirected to HTTPS with a 301; there is no redirect loop.
  • The certificate is valid and renews automatically.
  • There are no mixed content warnings.
  • HSTS was tried for a short period, then extended.
  • X-Content-Type-Options: nosniff is defined.
  • Framing is restricted with X-Frame-Options and frame-ancestors.
  • Referrer-Policy and Permissions-Policy are defined.
  • CSP is at least in report-only mode; violations are being reviewed.
  • The headers also arrive on subpages and error pages.

Frequently asked questions

Will adding headers slow my site down?

No. Headers are a few hundred bytes of text; they do not cause any measurable slowdown. HSTS even brings a small speed gain, because it skips the redirect step on later visits.

Should I add the X-XSS-Protection header?

Current browsers have stopped supporting this header; in some cases it could even cause problems. Use Content-Security-Policy instead.

I cannot use .htaccess; what can I do?

On servers such as Nginx, the same headers are defined in the server configuration with add_header. On shared hosting you can add them in your provider's panel or with help from the support team; if you use a CDN, the headers can also be added from the CDN panel.

A feature broke because of CSP; what should I do?

The violation message in the browser console shows which source was caught by which directive. Add that source to the relevant directive or move the inline script into a separate file. This is why it is important to start in report-only mode first.

BYK Yazılım Support Team
This guide is written and regularly reviewed by the BYK Yazılım support team. Last updated: 4 October 2026.

Related guides

Let us review your website together

BYK Yazılım builds corporate websites. Write to us with any questions about your site.

Contact us Our corporate website service