├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md ├── PULL_REQUEST_TEMPLATE.md └── stale.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples └── content_security_policy.rs ├── src ├── csp.rs └── lib.rs └── tests └── test.rs /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of 9 | experience, 10 | education, socio-economic status, nationality, personal appearance, race, 11 | religion, or sexual identity and orientation. 12 | 13 | ## Our Standards 14 | 15 | Examples of behavior that contributes to creating a positive environment 16 | include: 17 | 18 | - Using welcoming and inclusive language 19 | - Being respectful of differing viewpoints and experiences 20 | - Gracefully accepting constructive criticism 21 | - Focusing on what is best for the community 22 | - Showing empathy towards other community members 23 | 24 | Examples of unacceptable behavior by participants include: 25 | 26 | - The use of sexualized language or imagery and unwelcome sexual attention or 27 | advances 28 | - Trolling, insulting/derogatory comments, and personal or political attacks 29 | - Public or private harassment 30 | - Publishing others' private information, such as a physical or electronic 31 | address, without explicit permission 32 | - Other conduct which could reasonably be considered inappropriate in a 33 | professional setting 34 | 35 | 36 | ## Our Responsibilities 37 | 38 | Project maintainers are responsible for clarifying the standards of acceptable 39 | behavior and are expected to take appropriate and fair corrective action in 40 | response to any instances of unacceptable behavior. 41 | 42 | Project maintainers have the right and responsibility to remove, edit, or 43 | reject comments, commits, code, wiki edits, issues, and other contributions 44 | that are not aligned to this Code of Conduct, or to ban temporarily or 45 | permanently any contributor for other behaviors that they deem inappropriate, 46 | threatening, offensive, or harmful. 47 | 48 | ## Scope 49 | 50 | This Code of Conduct applies both within project spaces and in public spaces 51 | when an individual is representing the project or its community. Examples of 52 | representing a project or community include using an official project e-mail 53 | address, posting via an official social media account, or acting as an appointed 54 | representative at an online or offline event. Representation of a project may be 55 | further defined and clarified by project maintainers. 56 | 57 | ## Enforcement 58 | 59 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 60 | reported by contacting the project team at yoshuawuyts@gmail.com, or through 61 | IRC. All complaints will be reviewed and investigated and will result in a 62 | response that is deemed necessary and appropriate to the circumstances. The 63 | project team is obligated to maintain confidentiality with regard to the 64 | reporter of an incident. 65 | Further details of specific enforcement policies may be posted separately. 66 | 67 | Project maintainers who do not follow or enforce the Code of Conduct in good 68 | faith may face temporary or permanent repercussions as determined by other 69 | members of the project's leadership. 70 | 71 | ## Attribution 72 | 73 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, 74 | available at 75 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 76 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Contributions include code, documentation, answering user questions, running the 3 | project's infrastructure, and advocating for all types of users. 4 | 5 | The project welcomes all contributions from anyone willing to work in good faith 6 | with other contributors and the community. No contribution is too small and all 7 | contributions are valued. 8 | 9 | This guide explains the process for contributing to the project's GitHub 10 | Repository. 11 | 12 | - [Code of Conduct](#code-of-conduct) 13 | - [Bad Actors](#bad-actors) 14 | 15 | ## Code of Conduct 16 | The project has a [Code of Conduct](./CODE_OF_CONDUCT.md) that *all* 17 | contributors are expected to follow. This code describes the *minimum* behavior 18 | expectations for all contributors. 19 | 20 | As a contributor, how you choose to act and interact towards your 21 | fellow contributors, as well as to the community, will reflect back not only 22 | on yourself but on the project as a whole. The Code of Conduct is designed and 23 | intended, above all else, to help establish a culture within the project that 24 | allows anyone and everyone who wants to contribute to feel safe doing so. 25 | 26 | Should any individual act in any way that is considered in violation of the 27 | [Code of Conduct](./CODE_OF_CONDUCT.md), corrective actions will be taken. It is 28 | possible, however, for any individual to *act* in such a manner that is not in 29 | violation of the strict letter of the Code of Conduct guidelines while still 30 | going completely against the spirit of what that Code is intended to accomplish. 31 | 32 | Open, diverse, and inclusive communities live and die on the basis of trust. 33 | Contributors can disagree with one another so long as they trust that those 34 | disagreements are in good faith and everyone is working towards a common 35 | goal. 36 | 37 | ## Bad Actors 38 | All contributors to tacitly agree to abide by both the letter and 39 | spirit of the [Code of Conduct](./CODE_OF_CONDUCT.md). Failure, or 40 | unwillingness, to do so will result in contributions being respectfully 41 | declined. 42 | 43 | A *bad actor* is someone who repeatedly violates the *spirit* of the Code of 44 | Conduct through consistent failure to self-regulate the way in which they 45 | interact with other contributors in the project. In doing so, bad actors 46 | alienate other contributors, discourage collaboration, and generally reflect 47 | poorly on the project as a whole. 48 | 49 | Being a bad actor may be intentional or unintentional. Typically, unintentional 50 | bad behavior can be easily corrected by being quick to apologize and correct 51 | course *even if you are not entirely convinced you need to*. Giving other 52 | contributors the benefit of the doubt and having a sincere willingness to admit 53 | that you *might* be wrong is critical for any successful open collaboration. 54 | 55 | Don't be a bad actor. 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | Explain what is going on. 3 | 4 | ## Your Environment 5 | | Software | Version(s) | 6 | | ---------------- | ---------- | 7 | | armor | 8 | | Rustc | 9 | | Operating System | 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Did something not work as expected? 4 | --- 5 | 6 | # Bug Report 7 | ## Your Environment 8 | | Software | Version(s) | 9 | | ---------------- | ---------- | 10 | | armor | 11 | | Rustc | 12 | | Operating System | 13 | 14 | ## Expected Behavior 15 | Tell us what should have happened. 16 | 17 | ## Current Behavior 18 | Tell us what happens instead of the expected behavior. If you are seeing an 19 | error, please include the full error message and stack trace. 20 | 21 | ## Code Sample 22 | Please provide a code repository, gist, code snippet or sample files to 23 | reproduce the issue. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Want us to add something to armor? 4 | --- 5 | 6 | # Feature Request 7 | ## Summary 8 | One paragraph explanation of the feature. 9 | 10 | ## Motivation 11 | Why are we doing this? What use cases does it support? What is the expected 12 | outcome? 13 | 14 | ## Guide-level explanation 15 | Explain the proposal as if it was already included in the project and you 16 | were teaching it to another programmer. That generally means: 17 | 18 | - Introducing new named concepts. 19 | - Explaining the feature largely in terms of examples. 20 | - If applicable, provide sample error messages, deprecation warnings, or 21 | migration guidance. 22 | 23 | ## Reference-level explanation 24 | This is the technical portion of the feature request. Explain the design in 25 | sufficient detail that: 26 | 27 | - Its interaction with other features is clear. 28 | - It is reasonably clear how the feature would be implemented. 29 | - Corner cases are dissected by example. 30 | 31 | ## Drawbacks 32 | Why should we _not_ do this? 33 | 34 | ## Rationale and alternatives 35 | - Why is this design the best in the space of possible designs? 36 | - What other designs have been considered and what is the rationale for not 37 | choosing them? 38 | - What is the impact of not doing this? 39 | 40 | ## Unresolved Questions 41 | What related issues do you consider out of scope for this feature that could be 42 | addressed in the future independently of the solution that comes out of this 43 | feature? 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Have any questions regarding how armor works? 4 | --- 5 | 6 | # Question 7 | ## Your Environment 8 | | Software | Version(s) | 9 | | ---------------- | ---------- | 10 | | armor | 11 | | Rustc | 12 | | Operating System | 13 | 14 | ## Question 15 | Provide your question here. 16 | 17 | ## Context 18 | How has this issue affected you? What are you trying to accomplish? 19 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Motivation and Context 7 | 8 | 9 | 10 | ## Types of changes 11 | 12 | - [ ] Bug fix (non-breaking change which fixes an issue) 13 | - [ ] New feature (non-breaking change which adds functionality) 14 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 15 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | daysUntilStale: 90 4 | daysUntilClose: 7 5 | exemptLabels: 6 | - pinned 7 | - security 8 | exemptProjects: false 9 | exemptMilestones: false 10 | staleLabel: wontfix 11 | markComment: > 12 | This issue has been automatically marked as stale because it has not had 13 | recent activity. It will be closed if no further activity occurs. Thank you 14 | for your contributions. 15 | unmarkComment: false 16 | closeComment: false 17 | limitPerRun: 30 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | target/ 3 | tmp/ 4 | dist/ 5 | npm-debug.log* 6 | Cargo.lock 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | 5 | before_script: | 6 | rustup component add rustfmt-preview && 7 | rustup component add clippy-preview 8 | script: | 9 | cargo fmt -- --check && 10 | cargo clippy -- -D clippy && 11 | cargo build --verbose && 12 | cargo test --verbose 13 | cache: cargo 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2019-05-28, Version 1.1.0 2 | ### Commits 3 | - [[`f230c81244`](https://github.com/rustasync/armor/commit/f230c81244fad300d162f0f710a62051575b0842)] (cargo-release) version 1.1.0 (Yoshua Wuyts) 4 | - [[`9219da77bf`](https://github.com/rustasync/armor/commit/9219da77bf99b44b1994eedc1961557ace882fad)] Added referrer-policy as an optional header (#2) (Ricky) 5 | - [[`c2667a9743`](https://github.com/rustasync/armor/commit/c2667a9743693c4b5729e792485247706ed71031)] finalize (Yoshua Wuyts) 6 | - [[`88d9a0efc4`](https://github.com/rustasync/armor/commit/88d9a0efc4acaa1ed14df7c38ecd57231678da73)] done (Yoshua Wuyts) 7 | - [[`27148f701b`](https://github.com/rustasync/armor/commit/27148f701bb2c28e10a1079a6e8127cefc8965aa)] . (Yoshua Wuyts) 8 | 9 | ### Stats 10 | ```diff 11 | .github/CODE_OF_CONDUCT.md | 75 +++++++++++- 12 | .github/CONTRIBUTING.md | 55 ++++++++- 13 | .github/ISSUE_TEMPLATE.md | 9 +- 14 | .github/ISSUE_TEMPLATE/bug_report.md | 23 +++- 15 | .github/ISSUE_TEMPLATE/feature_request.md | 43 +++++++- 16 | .github/ISSUE_TEMPLATE/question.md | 18 +++- 17 | .github/PULL_REQUEST_TEMPLATE.md | 14 ++- 18 | .github/stale.yml | 17 +++- 19 | .gitignore | 7 +- 20 | .travis.yml | 13 ++- 21 | Cargo.toml | 17 +++- 22 | LICENSE-APACHE | 190 +++++++++++++++++++++++++++++- 23 | LICENSE-MIT | 21 +++- 24 | README.md | 54 ++++++++- 25 | src/lib.rs | 204 +++++++++++++++++++++++++++++++- 26 | tests/test.rs | 6 +- 27 | 16 files changed, 766 insertions(+) 28 | ``` 29 | 30 | 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "armor" 3 | version = "1.2.0" 4 | license = "MIT OR Apache-2.0" 5 | repository = "https://github.com/rustasync/armor" 6 | documentation = "https://docs.rs/armor" 7 | description = "HTTP Security Headers." 8 | keywords = ["security", "XSS", "helmet", "HTTP"] 9 | categories = ["asynchronous", "web-programming", "web-programming::http-server"] 10 | authors = ["Yoshua Wuyts "] 11 | readme = "README.md" 12 | edition = "2018" 13 | 14 | [dependencies] 15 | http = "0.1.17" 16 | serde = { version = "1.0", features = ["derive"] } 17 | serde_json = "1.0" 18 | 19 | [dev-dependencies] 20 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2019 Yoshua Wuyts 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Yoshua Wuyts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # armor 2 | 3 | [![crates.io version][1]][2] [![build status][3]][4] 4 | [![downloads][5]][6] [![docs.rs docs][7]][8] 5 | 6 | This crate has been deprecated in favor of `http-types`. See 7 | [http-types#98](https://github.com/http-rs/http-types/pull/98) for more 8 | details. 9 | 10 | --- 11 | 12 | HTTP Security Headers. Adapted from [helmetjs](https://helmetjs.github.io/). 13 | 14 | - [Documentation][8] 15 | - [Crates.io][2] 16 | - [Releases][releases] 17 | 18 | ## Examples 19 | __Basic usage__ 20 | ```rust 21 | let mut headers = http::HeaderMap::new(); 22 | armor::armor(&mut headers); 23 | assert_eq!(headers["X-Content-Type-Options"], "nosniff"); 24 | assert_eq!(headers["X-XSS-Protection"], "1; mode=block"); 25 | ``` 26 | 27 | ## Installation 28 | ```sh 29 | $ cargo add armor 30 | ``` 31 | 32 | ## Safety 33 | This crate uses ``#![deny(unsafe_code)]`` to ensure everything is implemented in 34 | 100% Safe Rust. 35 | 36 | ## Contributing 37 | Want to join us? Check out our ["Contributing" guide][contributing] and take a 38 | look at some of these issues: 39 | 40 | - [Issues labeled "good first issue"][good-first-issue] 41 | - [Issues labeled "help wanted"][help-wanted] 42 | 43 | ## References 44 | None. 45 | 46 | ## License 47 | [MIT](./LICENSE-MIT) OR [Apache-2.0](./LICENSE-APACHE) 48 | 49 | [1]: https://img.shields.io/crates/v/armor.svg?style=flat-square 50 | [2]: https://crates.io/crates/armor 51 | [3]: https://img.shields.io/travis/rustasync/armor/master.svg?style=flat-square 52 | [4]: https://travis-ci.org/rustasync/armor 53 | [5]: https://img.shields.io/crates/d/armor.svg?style=flat-square 54 | [6]: https://crates.io/crates/armor 55 | [7]: https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square 56 | [8]: https://docs.rs/armor 57 | 58 | [releases]: https://github.com/rustasync/armor/releases 59 | [contributing]: https://github.com/rustasync/armor/blob/master.github/CONTRIBUTING.md 60 | [good-first-issue]: https://github.com/rustasync/armor/labels/good%20first%20issue 61 | [help-wanted]: https://github.com/rustasync/armor/labels/help%20wanted 62 | -------------------------------------------------------------------------------- /examples/content_security_policy.rs: -------------------------------------------------------------------------------- 1 | use armor::csp; 2 | 3 | fn main() { 4 | let mut policy = armor::csp::new(); 5 | policy 6 | .default_src(csp::Source::SameOrigin) 7 | .default_src("areweasyncyet.rs") 8 | .script_src(csp::Source::SameOrigin) 9 | .script_src(csp::Source::UnsafeInline) 10 | .object_src(csp::Source::None) 11 | .base_uri(csp::Source::None) 12 | .upgrade_insecure_requests(); 13 | let mut headers = http::HeaderMap::new(); 14 | armor::armor(&mut headers); 15 | policy.apply(&mut headers); 16 | 17 | assert_eq!(headers["content-security-policy"], "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self' 'unsafe-inline'; upgrade-insecure-requests"); 18 | } 19 | -------------------------------------------------------------------------------- /src/csp.rs: -------------------------------------------------------------------------------- 1 | //! Apply `Content-Security-Policy` headers. 2 | //! 3 | //! `Content-Security-Policy` (CSP) HTTP headers are used to prevent cross-site 4 | //! injections. [Read more](https://helmetjs.github.io/docs/csp/) 5 | //! 6 | //! [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) 7 | //! 8 | //! # Examples 9 | //! 10 | //! ``` 11 | //! let mut policy = armor::csp::new() 12 | //! .default_src(armor::csp::Source::SameOrigin) 13 | //! .default_src("areweasyncyet.rs") 14 | //! .script_src(armor::csp::Source::SameOrigin) 15 | //! .object_src(armor::csp::Source::None) 16 | //! .base_uri(armor::csp::Source::None) 17 | //! .upgrade_insecure_requests(); 18 | //! 19 | //! let mut headers = http::HeaderMap::new(); 20 | //! policy.apply(&mut headers); 21 | //! 22 | //! assert_eq!(headers["content-security-policy"], "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self'; upgrade-insecure-requests"); 23 | //! ``` 24 | 25 | use http::HeaderMap; 26 | use serde::Serialize; 27 | use std::collections::HashMap; 28 | use std::fmt; 29 | 30 | /// Define source value 31 | /// 32 | /// [read more](https://content-security-policy.com) 33 | #[derive(Debug)] 34 | pub enum Source { 35 | /// Set source `'self'` 36 | SameOrigin, 37 | /// Set source `'src'` 38 | SRC, 39 | /// Set source `'none'` 40 | None, 41 | /// Set source `'unsafe-inline'` 42 | UnsafeInline, 43 | /// Set source `data:` 44 | Data, 45 | /// Set source `mediastream:` 46 | Mediastream, 47 | /// Set source `https:` 48 | HTTPS, 49 | /// Set source `blob:` 50 | Blob, 51 | /// Set source `filesystem:` 52 | Filesystem, 53 | /// Set source `'strict-dynamic'` 54 | StrictDynamic, 55 | /// Set source `'unsafe-eval'` 56 | UnsafeEval, 57 | /// Set source `*` 58 | Wildcard, 59 | } 60 | 61 | impl fmt::Display for Source { 62 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 63 | match *self { 64 | Source::SameOrigin => write!(f, "'self'"), 65 | Source::SRC => write!(f, "'src'"), 66 | Source::None => write!(f, "'none'"), 67 | Source::UnsafeInline => write!(f, "'unsafe-inline'"), 68 | Source::Data => write!(f, "data:"), 69 | Source::Mediastream => write!(f, "mediastream:"), 70 | Source::HTTPS => write!(f, "https:"), 71 | Source::Blob => write!(f, "blob:"), 72 | Source::Filesystem => write!(f, "filesystem:"), 73 | Source::StrictDynamic => write!(f, "'strict-dynamic'"), 74 | Source::UnsafeEval => write!(f, "'unsafe-eval'"), 75 | Source::Wildcard => write!(f, "*"), 76 | } 77 | } 78 | } 79 | 80 | impl AsRef for Source { 81 | fn as_ref(&self) -> &str { 82 | match *self { 83 | Source::SameOrigin => "'self'", 84 | Source::SRC => "'src'", 85 | Source::None => "'none'", 86 | Source::UnsafeInline => "'unsafe-inline'", 87 | Source::Data => "data:", 88 | Source::Mediastream => "mediastream:", 89 | Source::HTTPS => "https:", 90 | Source::Blob => "blob:", 91 | Source::Filesystem => "filesystem:", 92 | Source::StrictDynamic => "'strict-dynamic'", 93 | Source::UnsafeEval => "'unsafe-eval'", 94 | Source::Wildcard => "*", 95 | } 96 | } 97 | } 98 | 99 | /// Define `report-to` directive value 100 | /// 101 | /// [MDN | report-to](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to) 102 | #[derive(Serialize, Debug)] 103 | pub struct ReportTo { 104 | #[serde(skip_serializing_if = "Option::is_none")] 105 | group: Option, 106 | max_age: i32, 107 | endpoints: Vec, 108 | #[serde(skip_serializing_if = "Option::is_none")] 109 | include_subdomains: Option, 110 | } 111 | 112 | /// Define `endpoints` for `report-to` directive value 113 | /// 114 | /// [MDN | report-to](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to) 115 | #[derive(Serialize, Debug)] 116 | pub struct ReportToEndpoint { 117 | url: String, 118 | } 119 | 120 | /// Build the Content-Security-Policy 121 | #[derive(Debug)] 122 | pub struct ContentSecurityPolicy { 123 | policy: Vec, 124 | report_only_flag: bool, 125 | directives: HashMap>, 126 | } 127 | 128 | impl Default for ContentSecurityPolicy { 129 | /// Sets the Content-Security-Policy default to "script-src 'self'; object-src 'self'" 130 | fn default() -> Self { 131 | let policy = String::from("script-src 'self'; object-src 'self'"); 132 | ContentSecurityPolicy { 133 | policy: vec![policy], 134 | report_only_flag: false, 135 | directives: HashMap::new(), 136 | } 137 | } 138 | } 139 | 140 | impl ContentSecurityPolicy { 141 | /// Create a new instance. 142 | pub fn new() -> Self { 143 | Self { 144 | policy: Vec::new(), 145 | report_only_flag: false, 146 | directives: HashMap::new(), 147 | } 148 | } 149 | 150 | fn insert_directive>(&mut self, directive: &str, source: T) { 151 | let directive = String::from(directive); 152 | let directives = self.directives.entry(directive).or_insert_with(Vec::new); 153 | let source: String = source.as_ref().to_string(); 154 | directives.push(source); 155 | } 156 | 157 | /// Defines the Content-Security-Policy `base-uri` directive 158 | /// 159 | /// [MDN | base-uri](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri) 160 | pub fn base_uri>(&mut self, source: T) -> &mut Self { 161 | self.insert_directive("base-uri", source); 162 | self 163 | } 164 | 165 | /// Defines the Content-Security-Policy `block-all-mixed-content` directive 166 | /// 167 | /// [MDN | block-all-mixed-content](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content) 168 | pub fn block_all_mixed_content(&mut self) -> &mut Self { 169 | let policy = String::from("block-all-mixed-content"); 170 | self.policy.push(policy); 171 | self 172 | } 173 | 174 | /// Defines the Content-Security-Policy `connect-src` directive 175 | /// 176 | /// [MDN | connect-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src) 177 | pub fn connect_src>(&mut self, source: T) -> &mut Self { 178 | self.insert_directive("connect-src", source); 179 | self 180 | } 181 | 182 | /// Defines the Content-Security-Policy `default-src` directive 183 | /// 184 | /// [MDN | default-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src) 185 | pub fn default_src>(&mut self, source: T) -> &mut Self { 186 | self.insert_directive("default-src", source); 187 | self 188 | } 189 | 190 | /// Defines the Content-Security-Policy `font-src` directive 191 | /// 192 | /// [MDN | font-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src) 193 | pub fn font_src>(&mut self, source: T) -> &mut Self { 194 | self.insert_directive("font-src", source); 195 | self 196 | } 197 | 198 | /// Defines the Content-Security-Policy `form-action` directive 199 | /// 200 | /// [MDN | form-action](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action) 201 | pub fn form_action>(&mut self, source: T) -> &mut Self { 202 | self.insert_directive("form-action", source); 203 | self 204 | } 205 | 206 | /// Defines the Content-Security-Policy `frame-ancestors` directive 207 | /// 208 | /// [MDN | frame-ancestors](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) 209 | pub fn frame_ancestors>(&mut self, source: T) -> &mut Self { 210 | self.insert_directive("frame-ancestors", source); 211 | self 212 | } 213 | 214 | /// Defines the Content-Security-Policy `frame-src` directive 215 | /// 216 | /// [MDN | frame-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src) 217 | pub fn frame_src>(&mut self, source: T) -> &mut Self { 218 | self.insert_directive("frame-src", source); 219 | self 220 | } 221 | 222 | /// Defines the Content-Security-Policy `img-src` directive 223 | /// 224 | /// [MDN | img-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src) 225 | pub fn img_src>(&mut self, source: T) -> &mut Self { 226 | self.insert_directive("img-src", source); 227 | self 228 | } 229 | 230 | /// Defines the Content-Security-Policy `media-src` directive 231 | /// 232 | /// [MDN | media-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/media-src) 233 | pub fn media_src>(&mut self, source: T) -> &mut Self { 234 | self.insert_directive("media-src", source); 235 | self 236 | } 237 | 238 | /// Defines the Content-Security-Policy `object-src` directive 239 | /// 240 | /// [MDN | object-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src) 241 | pub fn object_src>(&mut self, source: T) -> &mut Self { 242 | self.insert_directive("object-src", source); 243 | self 244 | } 245 | 246 | /// Defines the Content-Security-Policy `plugin-types` directive 247 | /// 248 | /// [MDN | plugin-types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/plugin-types) 249 | pub fn plugin_types>(&mut self, source: T) -> &mut Self { 250 | self.insert_directive("plugin-types", source); 251 | self 252 | } 253 | 254 | /// Defines the Content-Security-Policy `require-sri-for` directive 255 | /// 256 | /// [MDN | require-sri-for](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/require-sri-for) 257 | pub fn require_sri_for>(&mut self, source: T) -> &mut Self { 258 | self.insert_directive("require-sri-for ", source); 259 | self 260 | } 261 | 262 | /// Defines the Content-Security-Policy `report-uri` directive 263 | /// 264 | /// [MDN | report-uri](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri) 265 | pub fn report_uri>(&mut self, uri: T) -> &mut Self { 266 | self.insert_directive("report-uri", uri); 267 | self 268 | } 269 | 270 | /// Defines the Content-Security-Policy `report-to` directive 271 | /// 272 | /// [MDN | report-to](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to) 273 | pub fn report_to(&mut self, endpoints: Vec) -> &mut Self { 274 | for endpoint in endpoints.iter() { 275 | match serde_json::to_string(&endpoint) { 276 | Ok(json) => { 277 | let policy = format!("report-to {}", json); 278 | self.policy.push(policy); 279 | } 280 | Err(error) => { 281 | println!("{:?}", error); 282 | } 283 | } 284 | } 285 | self 286 | } 287 | 288 | /// Defines the Content-Security-Policy `sandbox` directive 289 | /// 290 | /// [MDN | sandbox](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox) 291 | pub fn sandbox>(&mut self, source: T) -> &mut Self { 292 | self.insert_directive("sandbox", source); 293 | self 294 | } 295 | 296 | /// Defines the Content-Security-Policy `script-src` directive 297 | /// 298 | /// [MDN | script-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) 299 | pub fn script_src>(&mut self, source: T) -> &mut Self { 300 | self.insert_directive("script-src", source); 301 | self 302 | } 303 | 304 | /// Defines the Content-Security-Policy `style-src` directive 305 | /// 306 | /// [MDN | style-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src) 307 | pub fn style_src>(&mut self, source: T) -> &mut Self { 308 | self.insert_directive("style-src", source); 309 | self 310 | } 311 | 312 | /// Defines the Content-Security-Policy `upgrade-insecure-requests` directive 313 | /// 314 | /// [MDN | upgrade-insecure-requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests) 315 | pub fn upgrade_insecure_requests(&mut self) -> &mut Self { 316 | let policy = String::from("upgrade-insecure-requests"); 317 | self.policy.push(policy); 318 | self 319 | } 320 | 321 | /// Defines the Content-Security-Policy `worker-src` directive 322 | /// 323 | /// [MDN | worker-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/worker-src) 324 | pub fn worker_src>(&mut self, source: T) -> &mut Self { 325 | self.insert_directive("worker-src", source); 326 | self 327 | } 328 | 329 | /// Change the header to `Content-Security-Policy-Report-Only` 330 | pub fn report_only(&mut self) -> &mut Self { 331 | self.report_only_flag = true; 332 | self 333 | } 334 | 335 | /// Create and retrieve the policy value 336 | fn value(&mut self) -> String { 337 | for (directive, sources) in &self.directives { 338 | let policy = format!("{} {}", directive, sources.join(" ")); 339 | self.policy.push(policy); 340 | self.policy.sort(); 341 | } 342 | self.policy.join("; ") 343 | } 344 | 345 | /// Sets the `Content-Security-Policy` (CSP) HTTP header to prevent cross-site injections 346 | pub fn apply(&mut self, headers: &mut HeaderMap) { 347 | let val = self.value().parse().unwrap(); 348 | if !self.report_only_flag { 349 | headers.insert("Content-Security-Policy", val); 350 | } else { 351 | headers.insert("Content-Security-Policy-Report-Only", val); 352 | } 353 | } 354 | } 355 | 356 | /// Create a new instance. 357 | pub fn new() -> ContentSecurityPolicy { 358 | ContentSecurityPolicy::new() 359 | } 360 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! HTTP Security Headers. 2 | //! 3 | //! Adapted from [helmetjs](https://helmetjs.github.io/). 4 | //! 5 | //! ## Example 6 | //! ``` 7 | //! let mut headers = http::HeaderMap::new(); 8 | //! armor::armor(&mut headers); 9 | //! assert_eq!(headers["X-Content-Type-Options"], "nosniff"); 10 | //! assert_eq!(headers["X-XSS-Protection"], "1; mode=block"); 11 | //! ``` 12 | 13 | #![forbid(unsafe_code, future_incompatible)] 14 | #![deny(missing_debug_implementations, nonstandard_style, rust_2018_idioms)] 15 | #![warn(missing_docs, missing_doc_code_examples)] 16 | #![cfg_attr(test, deny(warnings))] 17 | 18 | use http::HeaderMap; 19 | pub mod csp; 20 | 21 | /// Apply all protections. 22 | /// 23 | /// ## Examples 24 | /// ``` 25 | /// let mut headers = http::HeaderMap::new(); 26 | /// armor::armor(&mut headers); 27 | /// assert_eq!(headers["X-Content-Type-Options"], "nosniff"); 28 | /// assert_eq!(headers["X-XSS-Protection"], "1; mode=block"); 29 | /// ``` 30 | pub fn armor(headers: &mut HeaderMap) { 31 | dns_prefetch_control(headers); 32 | dont_sniff_mimetype(headers); 33 | frameguard(headers, None); 34 | hide_powered_by(headers); 35 | hsts(headers); 36 | xss_filter(headers); 37 | } 38 | 39 | /// Disable browsers’ DNS prefetching by setting the `X-DNS-Prefetch-Control` header. 40 | /// 41 | /// [read more](https://helmetjs.github.io/docs/dns-prefetch-control/) 42 | /// 43 | /// ## Examples 44 | /// ``` 45 | /// let mut headers = http::HeaderMap::new(); 46 | /// armor::dns_prefetch_control(&mut headers); 47 | /// assert_eq!(headers["X-DNS-Prefetch-Control"], "on"); 48 | /// ``` 49 | #[inline] 50 | pub fn dns_prefetch_control(headers: &mut HeaderMap) { 51 | headers.insert("X-DNS-Prefetch-Control", "on".parse().unwrap()); 52 | } 53 | 54 | /// Set the frameguard level. 55 | #[derive(Debug, Clone)] 56 | pub enum FrameOptions { 57 | /// Set to `sameorigin` 58 | SameOrigin, 59 | /// Set to `deny` 60 | Deny, 61 | } 62 | 63 | /// Mitigates clickjacking attacks by setting the `X-Frame-Options` header. 64 | /// 65 | /// [read more](https://helmetjs.github.io/docs/frameguard/) 66 | /// 67 | /// ## Examples 68 | /// ``` 69 | /// let mut headers = http::HeaderMap::new(); 70 | /// armor::frameguard(&mut headers, None); 71 | /// assert_eq!(headers["X-Frame-Options"], "sameorigin"); 72 | /// ``` 73 | #[inline] 74 | pub fn frameguard(headers: &mut HeaderMap, guard: Option) { 75 | let kind = match guard { 76 | None | Some(FrameOptions::SameOrigin) => "sameorigin", 77 | Some(FrameOptions::Deny) => "deny", 78 | }; 79 | headers.insert("X-Frame-Options", kind.parse().unwrap()); 80 | } 81 | 82 | /// Removes the `X-Powered-By` header to make it slightly harder for attackers to see what 83 | /// potentially-vulnerable technology powers your site. 84 | /// 85 | /// [read more](https://helmetjs.github.io/docs/hide-powered-by/) 86 | /// 87 | /// ## Examples 88 | /// ``` 89 | /// let mut headers = http::HeaderMap::new(); 90 | /// headers.insert("X-Powered-By", "Tide/Rust".parse().unwrap()); 91 | /// armor::hide_powered_by(&mut headers); 92 | /// assert_eq!(headers.get("X-Powered-By"), None); 93 | /// ``` 94 | #[inline] 95 | pub fn hide_powered_by(headers: &mut HeaderMap) { 96 | headers.remove("X-Powered-By"); 97 | } 98 | 99 | /// Sets the `Strict-Transport-Security` header to keep your users on `HTTPS`. 100 | /// 101 | /// Note that the header won’t tell users on HTTP to switch to HTTPS, it will tell HTTPS users to 102 | /// stick around. Defaults to 60 days. 103 | /// 104 | /// [read more](https://helmetjs.github.io/docs/hsts/) 105 | /// 106 | /// ## Examples 107 | /// ``` 108 | /// let mut headers = http::HeaderMap::new(); 109 | /// armor::hsts(&mut headers); 110 | /// assert_eq!(headers["Strict-Transport-Security"], "max-age=5184000"); 111 | /// ``` 112 | #[inline] 113 | pub fn hsts(headers: &mut HeaderMap) { 114 | let val = "max-age=5184000".parse().unwrap(); 115 | headers.insert("Strict-Transport-Security", val); 116 | } 117 | 118 | /// Prevent browsers from trying to guess (“sniff”) the MIME type, which can have security 119 | /// implications. 120 | /// 121 | /// [read more](https://helmetjs.github.io/docs/dont-sniff-mimetype/) 122 | /// 123 | /// ## Examples 124 | /// ``` 125 | /// let mut headers = http::HeaderMap::new(); 126 | /// armor::dont_sniff_mimetype(&mut headers); 127 | /// assert_eq!(headers["X-Content-Type-Options"], "nosniff"); 128 | /// ``` 129 | #[inline] 130 | pub fn dont_sniff_mimetype(headers: &mut HeaderMap) { 131 | headers.insert("X-Content-Type-Options", "nosniff".parse().unwrap()); 132 | } 133 | 134 | /// Sets the `X-XSS-Protection` header to prevent reflected XSS attacks. 135 | /// 136 | /// [read more](https://helmetjs.github.io/docs/xss-filter/) 137 | /// 138 | /// ## Examples 139 | /// ``` 140 | /// let mut headers = http::HeaderMap::new(); 141 | /// armor::xss_filter(&mut headers); 142 | /// assert_eq!(headers["X-XSS-Protection"], "1; mode=block"); 143 | /// ``` 144 | #[inline] 145 | pub fn xss_filter(headers: &mut HeaderMap) { 146 | headers.insert("X-XSS-Protection", "1; mode=block".parse().unwrap()); 147 | } 148 | 149 | /// Set the Referrer-Policy level 150 | #[derive(Debug, Clone)] 151 | pub enum ReferrerOptions { 152 | /// Set to "no-referrer" 153 | NoReferrer, 154 | /// Set to "no-referrer-when-downgrade" the default 155 | NoReferrerDowngrade, 156 | /// Set to "same-origin" 157 | SameOrigin, 158 | /// Set to "origin" 159 | Origin, 160 | /// Set to "strict-origin" 161 | StrictOrigin, 162 | /// Set to "origin-when-cross-origin" 163 | CrossOrigin, 164 | /// Set to "strict-origin-when-cross-origin" 165 | StrictCrossOrigin, 166 | /// Set to "unsafe-url" 167 | UnsafeUrl, 168 | } 169 | 170 | /// Mitigates referrer leakage by controlling the referer[sic] header in links away from pages 171 | /// 172 | /// [read more](https://scotthelme.co.uk/a-new-security-header-referrer-policy/) 173 | /// 174 | /// [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) 175 | /// 176 | /// 177 | /// ## Examples 178 | /// ``` 179 | /// let mut headers = http::HeaderMap::new(); 180 | /// armor::referrer_policy(&mut headers, Some(armor::ReferrerOptions::UnsafeUrl)); 181 | /// armor::referrer_policy(&mut headers, None); 182 | /// let mut referrerValues: Vec<&str> = headers.get_all("Referrer-Policy").iter().map(|x| x.to_str().unwrap()).collect(); 183 | /// assert_eq!(referrerValues.sort(), vec!("unsafe-url", "no-referrer").sort()); 184 | /// ``` 185 | #[inline] 186 | pub fn referrer_policy(headers: &mut HeaderMap, referrer: Option) { 187 | let policy = match referrer { 188 | None | Some(ReferrerOptions::NoReferrer) => "no-referrer", 189 | Some(ReferrerOptions::NoReferrerDowngrade) => "no-referrer-when-downgrade", 190 | Some(ReferrerOptions::SameOrigin) => "same-origin", 191 | Some(ReferrerOptions::Origin) => "origin", 192 | Some(ReferrerOptions::StrictOrigin) => "strict-origin", 193 | Some(ReferrerOptions::CrossOrigin) => "origin-when-cross-origin", 194 | Some(ReferrerOptions::StrictCrossOrigin) => "strict-origin-when-cross-origin", 195 | Some(ReferrerOptions::UnsafeUrl) => "unsafe-url", 196 | }; 197 | 198 | // Allowing for multiple Referrer-Policy headers to be set 199 | // [Spec](https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values) Example #13 200 | if headers.contains_key("Referrer-Policy") { 201 | headers.append("Referrer-Policy", policy.parse().unwrap()); 202 | } else { 203 | headers.insert("Referrer-Policy", policy.parse().unwrap()); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | use armor::csp; 2 | use std::error::Error; 3 | 4 | #[test] 5 | fn should_work() -> Result<(), Box> { 6 | Ok(()) 7 | } 8 | 9 | #[test] 10 | fn csp_test() { 11 | let mut policy = armor::csp::new(); 12 | policy 13 | .default_src(csp::Source::SameOrigin) 14 | .default_src("areweasyncyet.rs") 15 | .script_src(csp::Source::SameOrigin) 16 | .script_src(csp::Source::UnsafeInline) 17 | .object_src(csp::Source::None) 18 | .base_uri(csp::Source::None) 19 | .upgrade_insecure_requests(); 20 | let mut headers = http::HeaderMap::new(); 21 | armor::armor(&mut headers); 22 | policy.apply(&mut headers); 23 | 24 | assert_eq!(headers["content-security-policy"], "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self' 'unsafe-inline'; upgrade-insecure-requests"); 25 | } 26 | --------------------------------------------------------------------------------