{"id":16863781,"url":"https://github.com/aidantwoods/secureheaders","last_synced_at":"2025-05-15T22:12:21.599Z","repository":{"id":56942761,"uuid":"71285369","full_name":"aidantwoods/SecureHeaders","owner":"aidantwoods","description":"A PHP library aiming to make the use of browser security features more accessible.","archived":false,"fork":false,"pushed_at":"2023-11-17T09:59:27.000Z","size":688,"stargazers_count":432,"open_issues_count":13,"forks_count":20,"subscribers_count":24,"default_branch":"main","last_synced_at":"2025-05-15T22:12:10.221Z","etag":null,"topics":["content-security-policy","cookie","csp","headers","hsts","samesite","secure","secure-cookie","secureheaders"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aidantwoods.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLogs/ChangeLog-2.0.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-10-18T19:48:23.000Z","updated_at":"2025-04-03T19:01:48.000Z","dependencies_parsed_at":"2024-01-13T07:07:48.791Z","dependency_job_id":null,"html_url":"https://github.com/aidantwoods/SecureHeaders","commit_stats":{"total_commits":381,"total_committers":6,"mean_commits":63.5,"dds":"0.13910761154855644","last_synced_commit":"93d833156fee711b14321a835548540e261eefb5"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidantwoods%2FSecureHeaders","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidantwoods%2FSecureHeaders/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidantwoods%2FSecureHeaders/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aidantwoods%2FSecureHeaders/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aidantwoods","download_url":"https://codeload.github.com/aidantwoods/SecureHeaders/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254430335,"owners_count":22069909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["content-security-policy","cookie","csp","headers","hsts","samesite","secure","secure-cookie","secureheaders"],"created_at":"2024-10-13T14:39:42.728Z","updated_at":"2025-05-15T22:12:21.484Z","avatar_url":"https://github.com/aidantwoods.png","language":"PHP","readme":"# SecureHeaders [![Build Status](https://travis-ci.org/aidantwoods/SecureHeaders.svg?branch=master)](https://travis-ci.org/aidantwoods/SecureHeaders) [![Build Status](https://ci.appveyor.com/api/projects/status/github/aidantwoods/SecureHeaders?branch=master\u0026svg=true\u0026retina=true)](https://ci.appveyor.com/project/aidantwoods/SecureHeaders)\nA PHP class aiming to make the use of browser security features more accessible.\n\nFor full documentation, please see the\n[Wiki](https://github.com/aidantwoods/SecureHeaders/wiki).\n\nA [demonstration](https://www.secureheaders.com/) with a sample configuration\nis also available.\n\n## What is a 'secure header'?\nSecure headers, are a\n[set of headers](https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers)\nthat configure browser security features. All of these headers can be used in\nany web application, and most can be deployed without any, or very minor code\nchanges. However some of the most effective ones *do* require code changes –\nespecially to implement well.\n\n## Features\n* Add/remove and manage headers easily\n* Build a Content Security Policy, or combine multiple together\n* Content Security Policy analysis\n* Easy integeration with arbitrary frameworks (take a look at the HttpAdapter)\n* Protect incorrectly set cookies\n* Strict mode\n* Safe mode prevents accidental long-term self-DOS when using HSTS, or HPKP\n* Receive warnings about missing, or misconfigured security headers\n\n## Methodology and Philosophy\nError messages are often a great way for a program to tell the programmer that\nsomething is wrong. Whether it's calling a variable that's not yet been\nassigned, or causing a fatal error by exhausting the memory allocation limit.\n\nBoth of these situations can usually be rectified very quickly by the\nprogrammer. The effort required to do so is greatly reduced because the program\ncommunicated exactly what the problem was, as soon as the programmer introduced\nthe bug. SecureHeaders aims to apply this concept to browser security features.\n\nUtilising the error reporting level set within PHP configuration, SecureHeaders\nwill generate `E_USER_WARNING` and `E_USER_NOTICE` level error messages to\ninform the programmer about either misconfigurations or lack of configuration.\n\nIn addition to error reporting, SecureHeaders will make some **safe** proactive\nchanges to certain headers, or even add new ones if they're missing.\n\n## Installation\n### Via Composer\n```\ncomposer require aidantwoods/secureheaders\n```\n### Other\nDownload [`SecureHeaders.phar`](https://github.com/aidantwoods/SecureHeaders/releases/latest), then\n```php\nrequire_once('SecureHeaders.phar');\n```\n\n## Sounds good, but let's see some of the code...\nHere is a good implementation example\n```php\n$headers = new SecureHeaders();\n$headers-\u003ehsts();\n$headers-\u003ecsp('default', 'self');\n$headers-\u003ecsp('script', 'https://my.cdn.org');\n$headers-\u003eapply();\n```\n\nThese few lines of code will take an application from a grade F, to a grade A\non Scott Helme's https://securityheaders.io/\n\n## Woah, that was easy! Tell me what it did...\nLet's break down the example above.\n\n'Out of the box', SecureHeaders will already do quite a lot (by running the\nfollowing code)\n```php\n$headers = new SecureHeaders();\n$headers-\u003eapply();\n```\n\n#### Automatic Headers and Errors\n\nWith such code, the following will occur:\n* Warnings will be issued (`E_USER_WARNING`)\n  \u003e **Warning:** Missing security header: 'Strict-Transport-Security'\n\n  \u003e **Warning:** Missing security header: 'Content-Security-Policy'\n\n* The following headers will be automatically added\n\n  ```\n  Expect-CT: max-age=0\n  Referrer-Policy: no-referrer\n  Referrer-Policy: strict-origin-when-cross-origin\n  X-Content-Type-Options:nosniff\n  X-Frame-Options:Deny\n  X-Permitted-Cross-Domain-Policies: none\n  X-XSS-Protection:1; mode=block\n  ```\n* The following header will also be removed (SecureHeaders will also attempt to\nremove the `Server` header, though it is unlikely this header will be under PHP\njurisdiction)\n\n  ```\n  X-Powered-By\n  ```\n\n#### Cookies\n\nAdditionally, if any cookies have been set (at any time before `-\u003eapply()` is\ncalled) e.g.\n```php\nsetcookie('auth', 'supersecretauthenticationstring');\n\n$headers = new SecureHeaders();\n$headers-\u003eapply();\n```\n\nEven though in the current PHP configuration, cookie flags `Secure` and\n`HTTPOnly` do **not** default to on, and despite the fact that\nPHP does not support the `SameSite` cookie attribute, the end result of the\n`Set-Cookie` header will be\n```\nSet-Cookie:auth=supersecretauthenticationstring; Secure; HttpOnly; SameSite=Lax\n```\n\nThese flags were inserted by SecureHeaders because the cookie name contained\nthe substring `auth`. Of course if that was a bad assumption, you can correct\nSecureHeaders' behaviour, or conversely you can tell SecureHeaders about some\nof your cookies that have less obvious names – but may need protecting in case\nof accidental missing flags.\n\nIf you enable [`-\u003estrictMode()`](#Strict-Mode) then the `SameSite` setting will\nbe set to strict (you can also upgrade this without using strict mode).\n\n#### Strict Mode\n\nStrict mode will enable settings that you **should** be using. It is highly\nadvisable to adjust your application to work with strict mode enabled.\n\nWhen enabled, strict mode will:\n* Auto-enable HSTS with a 1 year duration, and the `includeSubDomains`\n  and `preload` flags set. Note that this HSTS policy is made as a\n  header proposal, and can thus be removed or modified.\n\n* The source keyword `'strict-dynamic'` will also be added to the first\n  of the following directives that exist: `script-src`, `default-src`;\n  only if that directive also contains a nonce or hash source value, and\n  not otherwise.\n\n  This will disable the source whitelist in `script-src` in CSP3\n  compliant browsers. The use of whitelists in script-src is\n  [considered not to be an ideal practice][1], because they are often\n  trivial to bypass.\n\n  [1]: https://research.google.com/pubs/pub45542.html \"The Insecurity of\n  Whitelists and the Future of Content Security Policy\"\n\n  Don't forget to [manually submit](https://hstspreload.appspot.com/)\n  your domain to the HSTS preload list if you are using this option.\n\n* The default `SameSite` value injected into `-\u003eprotectedCookie` will\n  be changed from `SameSite=Lax` to `SameSite=Strict`.\n  See documentation on `-\u003eauto` to enable/disable injection\n  of `SameSite` and documentation on `-\u003esameSiteCookies` for more on specific\n  behaviour and to explicitly define this value manually, to override the\n  default.\n\n* Auto-enable Expect-CT with a 1 year duration, and the `enforce` flag\n  set. Note that this Expect-CT policy is made as a\n  header proposal, and can thus be removed or modified.\n\n#### Back to the example\n\nLet's take a look at those other three lines, the first of which was\n```php\n$headers-\u003ehsts();\n```\nThis enabled HSTS (Strict-Transport-Security) on the application for a duration\nof 1 year.\n\n*That sounds like something that might break things – I wouldn't want to\naccidentally enable that.*\n\n#### Safe Mode\n\nOkay, SecureHeaders has got you covered – use `$headers-\u003esafeMode();` to\nprevent headers being sent that will cause lasting effects.\n\nSo for example, if the following code was run (safe mode can be called at any\npoint before `-\u003eapply()` to be effective)\n```php\n$headers-\u003ehsts();\n$headers-\u003esafeMode();\n```\nHSTS would still be enabled (as asked), but would be limited to lasting 24\nhours.\n\nSecureHeaders would also generate the following notice\n\n\u003e **Notice:** HSTS settings were overridden because Safe-Mode is enabled.\n\u003e [Read about](https://scotthelme.co.uk/death-by-copy-paste/#hstsandpreloading)\n\u003e some common mistakes when setting HSTS via copy/paste, and ensure you\n\u003e [understand the details](https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet)\n\u003e and possible side effects of this security feature before using it.\n\n*What if I set it via a method not related to SecureHeaders? Can SecureHeaders\nstill enforce safe mode?*\n\nYup! SecureHeaders will look at the names and values of headers independently\nof its own built in functions that can be used to generate them.\n\nFor example, if I use PHPs built in header function to set HSTS for 1 year,\nfor all subdomains, and indicate consent to preload that rule into major\nbrowsers, and then (before or after setting that header) enable safe-mode...\n\n```php\nheader('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');\n$headers-\u003esafeMode();\n```\n\nThe same above notice will be generated, max-age will be modified to 1 day, and\nthe preload and includesubdomains flags will be removed.\n\n#### Content Security Policy\n\nThe final two lines to cover from the initial example are as follows\n```php\n$headers-\u003ecsp('default', 'self');\n$headers-\u003ecsp('script', 'https://my.cdn.org');\n```\nThese tell SecureHeaders that it should build a CSP (Content Security Policy)\nthat allows default assets to be loaded from the current domain (self), and\nthat scripts should be allowed from https://my.cdn.org.\n\nNote that if we had said http://my.cdn.org instead, then the following would\nhave been generated\n\n\u003e **Warning:** Content Security Policy contains the insecure protocol HTTP in a\n\u003e source value **http://my.cdn.org**; this can allow anyone to insert elements\n\u003e covered by the **script-src** directive into the page.\n\nSimilarly, if wildcards such as `'unsafe-inline'`, `https:`, or `*` are\nincluded – SecureHeaders will generate warnings to highlight these CSP bypasses.\n\nNote that the `-\u003ecsp` function is very diverse in what it will accept, to see\nsome more on that take a look at [Using CSP](#using-csp)\n\n## Sending the headers\nIn order to apply anything added through SecureHeaders, you'll need to call\n`-\u003eapply()`. By design, SecureHeaders doesn't have a construct function – so\neverything up until `-\u003eapply()` is called is just configuration. However, if you\ndon't want to have to remember to call this function, you can call\n`-\u003eapplyOnOutput()` instead, at any time. This will utilise PHP's `ob_start()`\nfunction to start output buffering. This lets SecureHeaders attatch itself to\nthe first instance of any piece of code that generates output – and prior to\nactually sending that output to the user, make sure all headers are sent, by\ncalling `-\u003eapply()` for you.\n\nBecause SecureHeaders doesn't have a construct function, you can easily\nimplement your own, via a simple class extension, e.g.\n```php\nclass CustomSecureHeaders extends SecureHeaders{\n    public function __construct()\n    {\n        $this-\u003eapplyOnOutput();\n        $this-\u003ehsts();\n        $this-\u003ecsp('default', 'self');\n        $this-\u003ecsp('script', 'https://my.cdn.org');\n    }\n}\n```\n\nThe above would implement the example discussed above, and would automatically\napply to any page that ran just one line of code\n```php\n$headers = new CustomSecureHeaders();\n```\n\nOf course, pages could add additional configuration too, and headers would only\nbe applied when the page started generating output.\n\n\n## Another Example\n\nIf the following CSP is created (note this probably isn't the best way to\ndefine a CSP of this size, see the array syntax that is available in the\nsection on [Using CSP](#using-csp))\n\n```php\n$headers-\u003ecsp('default', '*');\n$headers-\u003ecsp('script', 'unsafe-inline');\n$headers-\u003ecsp('script', 'http://insecure.cdn.org');\n$headers-\u003ecsp('style', 'https:');\n$headers-\u003ecsp('style', '*');\n$headers-\u003ecsp('report', 'https://valid-enforced-url.org');\n$headers-\u003ecspro('report', 'whatisthis');\n```\n\n```\nContent-Security-Policy:default-src *; script-src 'unsafe-inline'\nhttp://insecure.cdn.org; style-src https: *; report-uri\nhttps://valid-enforced-url.org;\n\nContent-Security-Policy-Report-Only:report-uri whatisthis;\n```\n\nThe following messages will be issued with regard to CSP:\n(level `E_USER_WARNING` and level `E_USER_NOTICE`)\n\n* The default-src directive contains a wildcard (so is a CSP bypass)\n\n  \u003e **Warning:** Content Security Policy contains a wildcard __*__ as a source\n  \u003e value in **default-src**; this can allow anyone to insert elements covered\n  \u003e by the **default-src** directive into the page.\n* The script-src directive contains an a flag that allows inline script (so is\na CSP bypass)\n\n  \u003e **Warning:** Content Security Policy contains the **'unsafe-inline'**\n  \u003e keyword in **script-src**, which prevents CSP protecting against the\n  \u003e injection of arbitrary code into the page.\n* The script-src directive contains an insecure resource as a source value\n(HTTP responses can be trivially spoofed – spoofing allows a bypass)\n\n  \u003e **Warning:** Content Security Policy contains the insecure protocol HTTP in\n  \u003e a source value **http://insecure.cdn.org**; this can allow anyone to insert\n  \u003e elements covered by the **script-src** directive into the page.\n* The style-src directive contains two wildcards (so is a CSP bypass) – both\nwildcards are listed\n\n  \u003e **Warning:** Content Security Policy contains the following wildcards\n  \u003e **https:**, __*__ as a source value in **style-src**; this can allow\n  \u003e anyone to insert elements covered by the style-src directive into the page.\n* The report only header was sent, but no/an invalid reporting address was\ngiven – preventing the report only header from doing anything useful in the wild\n\n  \u003e **Notice:** Content Security Policy Report Only header was sent, but an\n  \u003e invalid, or no reporting address was given. This header will not enforce\n  \u003e violations, and with no reporting address specified, the browser can only\n  \u003e report them locally in its console. Consider adding a reporting address to\n  \u003e make full use of this header.\n\n\n## Using CSP\n\nIf you're new to Content-Security-Policy then running your proposed policy\nthrough [Google's CSP Evaluator](https://csp-evaluator.withgoogle.com/) may be\na good idea.\n\nLet's take a look at a few ways of declaring the following CSP (or parts of\nit). Newlines and indentation added here for readability\n```\nContent-Security-Policy:\n    default-src 'self';\n    script-src 'self' https://my.cdn.org https://scripts.cdn.net https://other.cdn.com;\n    img-src https://images.cdn.xyz;\n    style-src https://amazingstylesheets.cdn.pizza;\n    base-uri 'self';\n    form-action 'none';\n    upgrade-insecure-requests;\n    block-all-mixed-content;\n```\n#### CSP as an array\n```php\n$myCSP = array(\n    'default-src' =\u003e [\n        \"'self'\"\n    ],\n    'script-src' =\u003e [\n        'self',\n        'https://my.cdn.org',\n        'https://scripts.cdn.net',\n        'https://other.cdn.com'\n    ],\n    'img-src' =\u003e ['https://images.cdn.xyz'],\n    'style-src' =\u003e 'https://amazingstylesheets.cdn.pizza',\n    'base' =\u003e 'self',\n    'form' =\u003e 'none',\n    'upgrade-insecure-requests' =\u003e null,\n    'block-all-mixed-content'\n);\n\n$headers-\u003ecsp($myCSP);\n```\n\nIn the above, we've specified the policy using an array in the way it makes the\nmost sense (bar some slight variation to demonstrate supported syntax).\nWe then passed our policy array to the `csp` function.\n\nWithin the array, take a look at `default-src`. This is the full directive name\n(the key of the array), and its source list is specified as an array containing\nsource values. In this case, the directive only has one source value, `'self'`,\nwhich is spelled out in full (note the single quotes within the string).\n\nIn this case, we've actually written a lot more than necessary – see the\ndirective `base` for comparison. The actual CSP directive here is `base-uri`,\nbut `base` is a supported shorthand by SecureHeaders. Secondly, we've omitted\nthe array syntax from the descending source list entirely – we only wanted to\ndeclare one valid source, so SecureHeaders supports foregoing the array\nstructure if its not useful. Additionally, we've made use of a shorthand within\nthe source value too – omitting the single quotes from the string's value (i.e.\n`self` is a shorthand for `'self'`).\n\nThere are two CSP 'flags' included also in this policy, namely\n`upgrade-insecure-requests` and `block-all-mixed-content`. These do not hold\nany source values (and would not be valid in CSP if they did). You can specify\nthese by either giving a source value of `null` (either as above, or an array\ncontaining only null as a source), or forgoing any mention of decedents\nentirely (as shown in `block-all-mixed-content`, which is written as-is).\nOnce a flag has been set, no sources may be added. Similarly once a directive\nhas been set, it may not become a flag. (This to prevent accidental loss of the\nentire source list).\n\nThe `csp` function also supports combining these CSP arrays, so the following\nwould combine the csp defined in `$myCSP`, and `$myOtherCSP`. You can combine\nas many csp arrays as you like by adding additional arguments.\n\n```php\n$headers-\u003ecsp($myCSP, $myOtherCSP);\n```\n\n#### CSP as ordered pairs\nUsing the same `csp` function as above, you can add sources to directives as\nfollows\n```php\n$headers-\u003ecsp('default', 'self');\n$headers-\u003ecsp('script', 'self');\n$headers-\u003ecsp('script', 'https://my.cdn.org');\n```\nor if you prefer to do this all in one line\n```php\n$headers-\u003ecsp('default', 'self', 'script', 'self', 'script', 'https://my.cdn.org');\n```\n\nNote that directives and sources are specified as ordered pairs here.\n\nIf you wanted to add a CSP flag in this way, simply use one of the following.\n```php\n$headers-\u003ecsp('upgrade-insecure-requests');\n$headers-\u003ecsp('block-all-mixed-content', null);\n```\nNote that the second way is necessary if embedded in a list of ordered pairs –\notherwise SecureHeaders can't tell what is a directive name or a source value.\ne.g. this would set `block-all-mixed-content` as a CSP flag, and\n`https://my.cdn.org` as a script-src source value.\n```php\n$headers-\u003ecsp('block-all-mixed-content', null, 'script', 'https://my.cdn.org');\n```\n\n**However**, the `csp` function also supports mixing these ordered pairs with\nthe array structure, and a string without a source at the end of the argument\nlist will also be treated as a flag. You could,\n*in perhaps an abuse of notation*, use the following to set two CSP flags and\nthe policy contained in the `$csp` array structure.\n\n```php\n$headers-\u003ecsp('block-all-mixed-content', $csp, 'upgrade-insecure-requests');\n```\n\n#### CSP as, uhh..\nThe CSP function aims to be as tolerant as possible, a CSP should be able to be\ncommunicated in whatever way is easiest to you.\n\nThat said, please use responsibly – the following is quite hard to read\n\n```php\n$myCSP = array(\n    'default-src' =\u003e [\n        \"'self'\"\n    ],\n    'script-src' =\u003e [\n        \"'self'\",\n        'https://my.cdn.org'\n    ],\n    'script' =\u003e [\n        'https://scripts.cdn.net'\n    ],\n);\n\n$myotherCSP = array(\n    'base' =\u003e 'self'\n);\n\n$whoopsIforgotThisCSP = array(\n    'form' =\u003e 'none'\n);\n\n$headers-\u003ecsp(\n    $myCSP, 'script', 'https://other.cdn.com',\n    ['block-all-mixed-content'], 'img',\n    'https://images.cdn.xyz', $myotherCSP\n);\n$headers-\u003ecsp(\n    'style', 'https://amazingstylesheets.cdn.pizza',\n    $whoopsIforgotThisCSP, 'upgrade-insecure-requests'\n);\n```\n\n#### Behaviour when a CSP header has already been set\n```php\nheader(\"Content-Security-Policy: default-src 'self'; script-src https://cdn.org 'self'\");\n$headers-\u003ecsp('script', 'https://another.domain.example.com');\n```\n\nThe above code will perform a merge the set CSP header, and the additional\n`script-src` value set in the final line. Producing the following merged\nCSP header\n```\nContent-Security-Policy: script-src https://another.domain.example.com https://cdn.org 'self'; default-src 'self'\n```\n\n#### Content-Security-Policy-Report-Only\nAll of the above is applicable to report only policies in exactly the same way.\nTo tell SecureHeaders that you're creating a report only policy, simply use\n`-\u003ecspro` in place of `-\u003ecsp`.\n\nAs an alternate method, you can also include the boolean `true`, or a non zero\ninteger (loosely compares to `true`) in the regular `-\u003ecsp` function's argument\nlist. The boolean `false` or the integer zero will signify enforced CSP\n(already the default). The left-most of these booleans or intgers will be taken\nas the mode. So to force enforced CSP (in-case you are unsure of the eventual\nvariable types in the CSP argument list), use\n`-\u003ecsp(false, arg1[, arg2[, ...]])` etc... or use zero in place of `false`.\nSimilarly, to force report-only (in-case you are unsure of the eventual\nvariable types in the CSP argument list) you can use either\n`-\u003ecspro(arg1[, arg2[, ...]])` or `-\u003ecsp(true, arg1[, arg2[, ...]])`.\n\nNote that while `-\u003ecsp` supports having its mode changed to report-only,\n`-\u003ecspro` does not (since is an alias for `-\u003ecsp` with report-only forced on).\n`-\u003ecsp` and `-\u003ecspro` are identical in their interpretation of the various\nstructures a Content-Security-Policy can be communicated in.\n\n## More on Usage\nFor full documentation, please see the\n[Wiki](https://github.com/aidantwoods/SecureHeaders/wiki)\n\n## Versioning\nThe SecureHeaders project will follow [Semantic Versioning 2], with\nthe following declared public API:\n\nAny method baring the [`@api`](https://phpdoc.org/docs/latest/references/phpdoc/tags/api.html)\nphpdoc tag.\n\nRoughtly speaking\n\n* Every public method in `Aidantwoods\\SecureHeaders\\SecureHeaders` (except `Aidantwoods\\SecureHeaders\\SecureHeaders::returnBuffer`)\n* Every public method in `Aidantwoods\\SecureHeaders\\Http`\n* Every public method in `Aidantwoods\\SecureHeaders\\HeaderBag`\n\nThis allows the main SecureHeaders class to be used as expected by [semver], and\nalso the HttpAdapter interface/implementation (for integration with anything)\nto be used as expected by [semver].\n\nAll other methods and properties are therefore non-public for the purposes of\n[semver]. That means that, e.g. methods with public visibility that are not in\nthe above scope are subject to change in a backwards incompatible way, without\na major version bump.\n\n[Semantic Versioning 2]: http://semver.org/\n[semver]: http://semver.org/\n\n## ChangeLog\nThe SecureHeaders project will follow\n[Keep a CHANGELOG](http://keepachangelog.com/) principles\n\nCheck out the `ChangeLogs/` folder, to see these.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faidantwoods%2Fsecureheaders","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faidantwoods%2Fsecureheaders","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faidantwoods%2Fsecureheaders/lists"}