├── .github └── workflows │ ├── codespell.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── controls └── nginx_spec.rb ├── inspec.yml ├── libraries └── nginx_lib.rb └── renovate.json /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Codespell - Spellcheck 3 | 4 | on: # yamllint disable-line rule:truthy 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | codespell: 12 | uses: "dev-sec/.github/.github/workflows/codespell.yml@main" 13 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: New release 3 | 4 | on: # yamllint disable-line rule:truthy 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | generate_changelog: 12 | uses: dev-sec/.github/.github/workflows/baseline-release.yml@main 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '0 6 * * *' 10 | 11 | jobs: 12 | test: 13 | uses: dev-sec/.github/.github/workflows/baseline-test.yml@main 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.librarian 2 | **/Puppetfile.lock 3 | **/.tmp 4 | Gemfile.lock 5 | Berksfile.lock 6 | inspec.lock 7 | nbproject 8 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AllCops: 3 | Exclude: 4 | - vendor/**/* 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [2.5.1](https://github.com/dev-sec/nginx-baseline/tree/2.5.1) (2023-05-02) 4 | 5 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.5.0...2.5.1) 6 | 7 | **Implemented enhancements:** 8 | 9 | - use centralised issue templates and workflows [\#55](https://github.com/dev-sec/nginx-baseline/pull/55) ([schurzi](https://github.com/schurzi)) 10 | 11 | **Merged pull requests:** 12 | 13 | - add spellchecking with codespell [\#57](https://github.com/dev-sec/nginx-baseline/pull/57) ([schurzi](https://github.com/schurzi)) 14 | - Configure Renovate [\#56](https://github.com/dev-sec/nginx-baseline/pull/56) ([renovate[bot]](https://github.com/apps/renovate)) 15 | - Change linting to Cookstyle [\#54](https://github.com/dev-sec/nginx-baseline/pull/54) ([schurzi](https://github.com/schurzi)) 16 | 17 | ## [2.5.0](https://github.com/dev-sec/nginx-baseline/tree/2.5.0) (2022-01-12) 18 | 19 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.4.1...2.5.0) 20 | 21 | **Implemented enhancements:** 22 | 23 | - add support for tls1.3 protocol [\#51](https://github.com/dev-sec/nginx-baseline/pull/51) ([rndmh3ro](https://github.com/rndmh3ro)) 24 | 25 | **Merged pull requests:** 26 | 27 | - use input instead of attribute [\#53](https://github.com/dev-sec/nginx-baseline/pull/53) ([micheelengronne](https://github.com/micheelengronne)) 28 | - update dhparams to 4096 [\#52](https://github.com/dev-sec/nginx-baseline/pull/52) ([rndmh3ro](https://github.com/rndmh3ro)) 29 | - fix rubocop error for Rakefile [\#49](https://github.com/dev-sec/nginx-baseline/pull/49) ([schurzi](https://github.com/schurzi)) 30 | - add dependency to chef-config for CI [\#48](https://github.com/dev-sec/nginx-baseline/pull/48) ([schurzi](https://github.com/schurzi)) 31 | - use version tag for changelog action [\#47](https://github.com/dev-sec/nginx-baseline/pull/47) ([schurzi](https://github.com/schurzi)) 32 | - Fix lint [\#46](https://github.com/dev-sec/nginx-baseline/pull/46) ([schurzi](https://github.com/schurzi)) 33 | - GitHub action [\#45](https://github.com/dev-sec/nginx-baseline/pull/45) ([rndmh3ro](https://github.com/rndmh3ro)) 34 | 35 | ## [2.4.1](https://github.com/dev-sec/nginx-baseline/tree/2.4.1) (2021-01-18) 36 | 37 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.4.0...2.4.1) 38 | 39 | **Merged pull requests:** 40 | 41 | - softcoded nginx path [\#43](https://github.com/dev-sec/nginx-baseline/pull/43) ([micheelengronne](https://github.com/micheelengronne)) 42 | 43 | ## [2.4.0](https://github.com/dev-sec/nginx-baseline/tree/2.4.0) (2020-11-08) 44 | 45 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.3.4...2.4.0) 46 | 47 | **Implemented enhancements:** 48 | 49 | - add fedora to valid users library [\#42](https://github.com/dev-sec/nginx-baseline/pull/42) ([rndmh3ro](https://github.com/rndmh3ro)) 50 | 51 | ## [2.3.4](https://github.com/dev-sec/nginx-baseline/tree/2.3.4) (2020-07-23) 52 | 53 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.3.3...2.3.4) 54 | 55 | ## [2.3.3](https://github.com/dev-sec/nginx-baseline/tree/2.3.3) (2020-07-13) 56 | 57 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.3.2...2.3.3) 58 | 59 | **Merged pull requests:** 60 | 61 | - Change default: to value: [\#41](https://github.com/dev-sec/nginx-baseline/pull/41) ([enzomignogna](https://github.com/enzomignogna)) 62 | 63 | ## [2.3.2](https://github.com/dev-sec/nginx-baseline/tree/2.3.2) (2020-06-18) 64 | 65 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.3.1...2.3.2) 66 | 67 | **Merged pull requests:** 68 | 69 | - version alignment [\#40](https://github.com/dev-sec/nginx-baseline/pull/40) ([micheelengronne](https://github.com/micheelengronne)) 70 | 71 | ## [2.3.1](https://github.com/dev-sec/nginx-baseline/tree/2.3.1) (2020-06-18) 72 | 73 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.3.0...2.3.1) 74 | 75 | **Closed issues:** 76 | 77 | - Profile fails `inspec json` [\#33](https://github.com/dev-sec/nginx-baseline/issues/33) 78 | 79 | **Merged pull requests:** 80 | 81 | - github actions release [\#39](https://github.com/dev-sec/nginx-baseline/pull/39) ([micheelengronne](https://github.com/micheelengronne)) 82 | - Declare control source as UTF-8 encoding. [\#34](https://github.com/dev-sec/nginx-baseline/pull/34) ([james-stocks](https://github.com/james-stocks)) 83 | 84 | ## [2.3.0](https://github.com/dev-sec/nginx-baseline/tree/2.3.0) (2019-05-15) 85 | 86 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.2.0...2.3.0) 87 | 88 | **Merged pull requests:** 89 | 90 | - Bump version to 2.3.0 and switch to inspec 3 for check [\#32](https://github.com/dev-sec/nginx-baseline/pull/32) ([alexpop](https://github.com/alexpop)) 91 | - Templates [\#30](https://github.com/dev-sec/nginx-baseline/pull/30) ([rndmh3ro](https://github.com/rndmh3ro)) 92 | - remove test for hardening.conf file [\#28](https://github.com/dev-sec/nginx-baseline/pull/28) ([rndmh3ro](https://github.com/rndmh3ro)) 93 | - use parse\_config instead of parse\_config\_file [\#27](https://github.com/dev-sec/nginx-baseline/pull/27) ([rndmh3ro](https://github.com/rndmh3ro)) 94 | - Make nginx-14 and nginx-16 disabled by default based on dev-sec/nginx-baseline\#21 [\#26](https://github.com/dev-sec/nginx-baseline/pull/26) ([woneill](https://github.com/woneill)) 95 | 96 | ## [2.2.0](https://github.com/dev-sec/nginx-baseline/tree/2.2.0) (2018-06-26) 97 | 98 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.1.0...2.2.0) 99 | 100 | **Closed issues:** 101 | 102 | - client\_max\_body\_size 1k disallows file uploads [\#13](https://github.com/dev-sec/nginx-baseline/issues/13) 103 | 104 | **Merged pull requests:** 105 | 106 | - Duplicated control 'nginx-11' [\#24](https://github.com/dev-sec/nginx-baseline/pull/24) ([pbanderas](https://github.com/pbanderas)) 107 | - Control label 'nginx-07' is used twice [\#22](https://github.com/dev-sec/nginx-baseline/pull/22) ([woneill](https://github.com/woneill)) 108 | 109 | ## [2.1.0](https://github.com/dev-sec/nginx-baseline/tree/2.1.0) (2017-11-19) 110 | 111 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.0.2...2.1.0) 112 | 113 | **Merged pull requests:** 114 | 115 | - More nginx controls, add attribute client\_max\_body\_size [\#19](https://github.com/dev-sec/nginx-baseline/pull/19) ([atomic111](https://github.com/atomic111)) 116 | - use recommended spdx license identifier [\#18](https://github.com/dev-sec/nginx-baseline/pull/18) ([chris-rock](https://github.com/chris-rock)) 117 | - Fix deprecation warnings. [\#17](https://github.com/dev-sec/nginx-baseline/pull/17) ([tmclaugh](https://github.com/tmclaugh)) 118 | 119 | ## [2.0.2](https://github.com/dev-sec/nginx-baseline/tree/2.0.2) (2017-05-08) 120 | 121 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.0.1...2.0.2) 122 | 123 | **Merged pull requests:** 124 | 125 | - update metadata [\#16](https://github.com/dev-sec/nginx-baseline/pull/16) ([chris-rock](https://github.com/chris-rock)) 126 | - restrict ruby testing to version 2.3.3 and update gemfile [\#15](https://github.com/dev-sec/nginx-baseline/pull/15) ([atomic111](https://github.com/atomic111)) 127 | 128 | ## [2.0.1](https://github.com/dev-sec/nginx-baseline/tree/2.0.1) (2016-12-22) 129 | 130 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2.0.0...2.0.1) 131 | 132 | **Closed issues:** 133 | 134 | - Tests skipped if command nginx not in PATH [\#12](https://github.com/dev-sec/nginx-baseline/issues/12) 135 | 136 | **Merged pull requests:** 137 | 138 | - readme update, change log & tooling [\#14](https://github.com/dev-sec/nginx-baseline/pull/14) ([chris-rock](https://github.com/chris-rock)) 139 | - fix typo [\#11](https://github.com/dev-sec/nginx-baseline/pull/11) ([rndmh3ro](https://github.com/rndmh3ro)) 140 | 141 | ## [2.0.0](https://github.com/dev-sec/nginx-baseline/tree/2.0.0) (2016-05-03) 142 | 143 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/1.0.0...2.0.0) 144 | 145 | **Merged pull requests:** 146 | 147 | - migrate to inspec profile [\#10](https://github.com/dev-sec/nginx-baseline/pull/10) ([atomic111](https://github.com/atomic111)) 148 | 149 | ## [1.0.0](https://github.com/dev-sec/nginx-baseline/tree/1.0.0) (2015-10-15) 150 | 151 | [Full Changelog](https://github.com/dev-sec/nginx-baseline/compare/2661c2a3199aa2dd9823f292c15c786a785149ab...1.0.0) 152 | 153 | 154 | 155 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 156 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'cookstyle' 6 | gem 'highline' 7 | gem 'rack' 8 | gem 'rake' 9 | gem 'rubocop' 10 | 11 | group :tools do 12 | gem 'github_changelog_generator' 13 | gem 'pry-coolline' 14 | end 15 | 16 | source 'https://packagecloud.io/cinc-project/stable' do 17 | gem 'chef-config' 18 | gem 'cinc-auditor-bin' 19 | end 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DevSec Nginx Baseline 2 | ===================== 3 | 4 | This Compliance Profile ensures, that all hardening projects keep the same quality. 5 | 6 | - https://github.com/dev-sec/ansible-nginx-hardening 7 | - https://github.com/dev-sec/chef-nginx-hardening 8 | - https://github.com/dev-sec/puppet-nginx-hardening 9 | 10 | ## Standalone Usage 11 | 12 | This Compliance Profile requires [InSpec](https://github.com/chef/inspec) for execution: 13 | 14 | ``` 15 | $ git clone https://github.com/dev-sec/nginx-baseline 16 | $ inspec exec nginx-baseline 17 | ``` 18 | 19 | You can also execute the profile directly from Github: 20 | 21 | ``` 22 | $ inspec exec https://github.com/dev-sec/nginx-baseline 23 | ``` 24 | 25 | ## License and Author 26 | 27 | * Author:: Patrick Muench 28 | * Author:: Dominik Richter 29 | * Author:: Christoph Hartmann 30 | 31 | * Copyright 2014-2016, The Hardening Framework Team 32 | 33 | Licensed under the Apache License, Version 2.0 (the "License"); 34 | you may not use this file except in compliance with the License. 35 | You may obtain a copy of the License at 36 | 37 | http://www.apache.org/licenses/LICENSE-2.0 38 | 39 | Unless required by applicable law or agreed to in writing, software 40 | distributed under the License is distributed on an "AS IS" BASIS, 41 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42 | See the License for the specific language governing permissions and 43 | limitations under the License. 44 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # frozen_string_literal: true 3 | 4 | require 'cookstyle' 5 | require 'rake/testtask' 6 | require 'rubocop/rake_task' 7 | 8 | # Rubocop 9 | desc 'Run Rubocop lint checks' 10 | task :rubocop do 11 | RuboCop::RakeTask.new 12 | end 13 | 14 | RuboCop::RakeTask.new(:cookstyle) do |task| 15 | task.options << '--display-cop-names' 16 | end 17 | 18 | # lint the project 19 | desc 'Run robocop linter' 20 | task lint: [:rubocop] 21 | 22 | # run tests 23 | task default: [:lint, 'test:check'] 24 | 25 | namespace :test do 26 | # run inspec check to verify that the profile is properly configured 27 | task :check do 28 | require 'inspec' 29 | puts "Checking profile with InSpec Version: #{Inspec::VERSION}" 30 | profile = Inspec::Profile.for_target('.', backend: Inspec::Backend.create(Inspec::Config.mock)) 31 | pp profile.check 32 | end 33 | end 34 | 35 | task :changelog do 36 | # Automatically generate a changelog for this project. Only loaded if 37 | # the necessary gem is installed. By default its picking up the version from 38 | # inspec.yml. You can override that behavior with `rake changelog to=1.2.0` 39 | 40 | require 'yaml' 41 | metadata = YAML.load_file('inspec.yml') 42 | v = ENV['to'] || metadata['version'] 43 | puts " * Generating changelog for version #{v}" 44 | require 'github_changelog_generator/task' 45 | GitHubChangelogGenerator::RakeTask.new :changelog do |config| 46 | config.future_release = v 47 | config.user = 'dev-sec' 48 | config.project = 'nginx-baseline' 49 | end 50 | Rake::Task[:changelog].execute 51 | rescue LoadError 52 | puts '>>>>> GitHub Changelog Generator not loaded, omitting tasks' 53 | end 54 | -------------------------------------------------------------------------------- /controls/nginx_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Copyright:: 2015, Patrick Muench 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # author: Christoph Hartmann 18 | # author: Dominik Richter 19 | # author: Patrick Muench 20 | 21 | title 'NGINX server config' 22 | 23 | # attributes 24 | CLIENT_MAX_BODY_SIZE = input( 25 | 'client_max_body_size', 26 | description: 'Sets the maximum allowed size of the client request body, specified in the “Content-Length” request header field. If the size in a request exceeds the configured value, the 413 (Request Entity Too Large) error is returned to the client. Please be aware that browsers cannot correctly display this error. Setting size to 0 disables checking of client request body size.', 27 | value: '1k' 28 | ) 29 | 30 | CLIENT_BODY_BUFFER_SIZE = input( 31 | 'client_body_buffer_size', 32 | description: 'Sets buffer size for reading client request body. In case the request body is larger than the buffer, the whole body or only its part is written to a temporary file. By default, buffer size is equal to two memory pages. This is 8K on x86, other 32-bit platforms, and x86-64. It is usually 16K on other 64-bit platforms.', 33 | value: '1k' 34 | ) 35 | 36 | CLIENT_HEADER_BUFFER_SIZE = input( 37 | 'client_header_buffer_size', 38 | description: 'Sets buffer size for reading client request header. For most requests, a buffer of 1K bytes is enough. However, if a request includes long cookies, or comes from a WAP client, it may not fit into 1K. If a request line or a request header field does not fit into this buffer then larger buffers, configured by the large_client_header_buffers directive, are allocated.', 39 | value: '1k' 40 | ) 41 | 42 | LARGE_CLIENT_HEADER_BUFFER = input( 43 | 'large_client_header_buffers', 44 | description: 'Sets the maximum number and size of buffers used for reading large client request header. A request line cannot exceed the size of one buffer, or the 414 (Request-URI Too Large) error is returned to the client. A request header field cannot exceed the size of one buffer as well, or the 400 (Bad Request) error is returned to the client. Buffers are allocated only on demand. By default, the buffer size is equal to 8K bytes. If after the end of request processing a connection is transitioned into the keep-alive state, these buffers are released.', 45 | value: '2 1k' 46 | ) 47 | 48 | KEEPALIVE_TIMEOUT = input( 49 | 'keepalive_timeout', 50 | description: 'The first parameter sets a timeout during which a keep-alive client connection will stay open on the server side. The zero value disables keep-alive client connections. The optional second parameter sets a value in the “Keep-Alive: timeout=time” response header field. Two parameters may differ.', 51 | value: '5 5' 52 | ) 53 | 54 | CLIENT_BODY_TIMEOUT = input( 55 | 'client_body_timeout', 56 | description: 'Defines a timeout for reading client request body. The timeout is set only for a period between two successive read operations, not for the transmission of the whole request body. If a client does not transmit anything within this time, the 408 (Request Time-out) error is returned to the client.', 57 | value: '10' 58 | ) 59 | 60 | CLIENT_HEADER_TIMEOUT = input( 61 | 'client_header_timeout', 62 | description: 'Defines a timeout for reading client request header. If a client does not transmit the entire header within this time, the 408 (Request Time-out) error is returned to the client.', 63 | value: '10' 64 | ) 65 | 66 | SEND_TIMEOUT = input( 67 | 'send_timeout', 68 | description: 'Sets a timeout for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. If the client does not receive anything within this time, the connection is closed.', 69 | value: '10' 70 | ) 71 | 72 | HTTP_METHODS = input( 73 | 'http_methods', 74 | description: 'Specify the used HTTP methods', 75 | value: 'GET\|HEAD\|POST' 76 | ) 77 | 78 | HTTP_METHODS_CHECK = input( 79 | 'http_methods_check', 80 | description: 'Defines if http_methods should be checked in the nginx configuration', 81 | value: false 82 | ) 83 | 84 | NGINX_COOKIE_FLAG_MODULE = input( 85 | 'nginx_cookie_flag_module', 86 | description: 'Defines if nginx has been compiled with nginx_cookie_flag_module', 87 | value: false 88 | ) 89 | 90 | only_if do 91 | command('nginx').exist? 92 | end 93 | 94 | # determine all required paths 95 | nginx_path = input('nginx_path', value: '/etc/nginx', description: 'Default nginx configurations path') 96 | nginx_conf = File.join(nginx_path, 'nginx.conf') 97 | nginx_confd = File.join(nginx_path, 'conf.d') 98 | nginx_enabled = File.join(nginx_path, 'sites-enabled') 99 | nginx_parsed_config = command('nginx -T').stdout 100 | 101 | options = { 102 | assignment_regex: /^\s*([^:]*?)\s*\ \s*(.*?)\s*;$/, 103 | } 104 | 105 | options_add_header = { 106 | assignment_regex: /^\s*([^:]*?)\s*\ \s*(.*?)\s*;$/, 107 | multiple_values: true, 108 | } 109 | 110 | control 'nginx-01' do 111 | impact 1.0 112 | title 'Running worker process as non-privileged user' 113 | desc 'The NGINX worker processes should run as non-privileged user. In case of compromise of the process, an attacker has full access to the system.' 114 | describe user(nginx_lib.valid_users) do 115 | it { should exist } 116 | end 117 | describe parse_config_file(nginx_conf, options) do 118 | its('user') { should eq nginx_lib.valid_users } 119 | end 120 | 121 | describe parse_config_file(nginx_conf, options) do 122 | its('group') { should_not eq 'root' } 123 | end 124 | end 125 | 126 | control 'nginx-02' do 127 | impact 1.0 128 | title 'Check NGINX config file owner, group and permissions.' 129 | desc 'The NGINX config file should owned by root, only be writable by owner and not write- and readable by others.' 130 | describe file(nginx_conf) do 131 | it { should be_owned_by 'root' } 132 | it { should be_grouped_into 'root' } 133 | it { should_not be_readable.by('others') } 134 | it { should_not be_writable.by('others') } 135 | it { should_not be_executable.by('others') } 136 | end 137 | end 138 | 139 | control 'nginx-03' do 140 | impact 1.0 141 | title 'Nginx default files' 142 | desc 'Remove the default nginx config files.' 143 | describe file(File.join(nginx_confd, 'default.conf')) do 144 | it { should_not be_file } 145 | end 146 | 147 | describe file(File.join(nginx_enabled, 'default')) do 148 | it { should_not be_file } 149 | end 150 | end 151 | 152 | control 'nginx-04' do 153 | impact 1.0 154 | title 'Check for multiple instances' 155 | desc 'Different instances of the nginx webserver should run in separate environments' 156 | describe command('ps aux | egrep "nginx: master" | egrep -v "grep" | wc -l') do 157 | its(:stdout) { should match(/^1$/) } 158 | end 159 | end 160 | 161 | control 'nginx-05' do 162 | impact 1.0 163 | title 'Disable server_tokens directive' 164 | desc 'Disables emitting nginx version in error messages and in the “Server” response header field.' 165 | describe parse_config(nginx_parsed_config, options) do 166 | its('server_tokens') { should eq 'off' } 167 | end 168 | end 169 | 170 | control 'nginx-06' do 171 | impact 1.0 172 | title 'Prevent buffer overflow attacks' 173 | desc 'Buffer overflow attacks are made possible by writing data to a buffer and exceeding that buffer boundary and overwriting memory fragments of a process. To prevent this in nginx we can set buffer size limitations for all clients.' 174 | describe parse_config(nginx_parsed_config, options) do 175 | its('client_body_buffer_size') { should eq CLIENT_BODY_BUFFER_SIZE } 176 | end 177 | describe parse_config(nginx_parsed_config, options) do 178 | its('client_max_body_size') { should eq CLIENT_MAX_BODY_SIZE } 179 | end 180 | describe parse_config(nginx_parsed_config, options) do 181 | its('client_header_buffer_size') { should eq CLIENT_HEADER_BUFFER_SIZE } 182 | end 183 | describe parse_config(nginx_parsed_config, options) do 184 | its('large_client_header_buffers') { should eq LARGE_CLIENT_HEADER_BUFFER } 185 | end 186 | end 187 | 188 | control 'nginx-07' do 189 | impact 1.0 190 | title 'Control simultaneous connections' 191 | desc 'NginxHttpLimitZone module to limit the number of simultaneous connections for the assigned session or as a special case, from one IP address.' 192 | describe parse_config(nginx_parsed_config, options) do 193 | its('limit_conn_zone') { should eq '$binary_remote_addr zone=default:10m' } 194 | end 195 | describe parse_config(nginx_parsed_config, options) do 196 | its('limit_conn') { should eq 'default 5' } 197 | end 198 | end 199 | 200 | control 'nginx-08' do 201 | impact 1.0 202 | title 'Prevent clickjacking' 203 | desc 'Do not allow the browser to render the page inside an frame or iframe.' 204 | describe parse_config(nginx_parsed_config, options_add_header) do 205 | its('add_header') { should include 'X-Frame-Options SAMEORIGIN' } 206 | end 207 | end 208 | 209 | control 'nginx-09' do 210 | impact 1.0 211 | title 'Enable Cross-site scripting filter' 212 | desc 'This header is used to configure the built in reflective XSS protection. This tells the browser to block the response if it detects an attack rather than sanitising the script.' 213 | describe parse_config(nginx_parsed_config, options_add_header) do 214 | its('add_header') { should include 'X-XSS-Protection "1; mode=block"' } 215 | end 216 | end 217 | 218 | control 'nginx-10' do 219 | impact 1.0 220 | title 'Disable content-type sniffing' 221 | desc 'It prevents browser from trying to mime-sniff the content-type of a response away from the one being declared by the server. It reduces exposure to drive-by downloads and the risks of user uploaded content that, with clever naming, could be treated as a different content-type, like an executable.' 222 | describe parse_config(nginx_parsed_config, options_add_header) do 223 | its('add_header') { should include 'X-Content-Type-Options nosniff' } 224 | end 225 | end 226 | 227 | control 'nginx-12' do 228 | impact 1.0 229 | title 'TLS Protocols' 230 | desc 'When choosing a cipher during an SSLv3 or TLSv1 handshake, normally the client\'s preference is used. If this directive is enabled, the server\'s preference will be used instead.' 231 | ref 'SSL Hardening config', url: 'https://mozilla.github.io/server-side-tls/ssl-config-generator/' 232 | describe parse_config(nginx_parsed_config, options) do 233 | its('ssl_protocols') { should be_in ['TLSv1.3', 'TLSv1.2', 'TLSv1.2 TLSv1.3', 'TLSv1.3 TLSv1.2'] } 234 | its('ssl_session_tickets') { should eq 'off' } 235 | its('ssl_ciphers') { should eq '\'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256\'' } 236 | its('ssl_prefer_server_ciphers') { should eq 'on' } 237 | its('ssl_dhparam') { should eq '/etc/nginx/dh4096.pem' } 238 | end 239 | end 240 | 241 | control 'nginx-13' do 242 | impact 1.0 243 | title 'Add HSTS Header' 244 | desc 'HTTP Strict Transport Security (HSTS) is a web security policy mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure HTTPS connections, and never via the insecure HTTP protocol. HSTS is an IETF standards track protocol and is specified in RFC 6797.' 245 | describe parse_config(nginx_parsed_config, options_add_header) do 246 | its('add_header') { should include 'Strict-Transport-Security max-age=15768000' } 247 | end 248 | end 249 | 250 | control 'nginx-14' do 251 | impact 1.0 252 | title 'Disable insecure HTTP-methods' 253 | desc 'Disable insecure HTTP-methods and allow only necessary methods.' 254 | ref 'OWASP HTTP Methods', url: 'https://www.owasp.org/index.php/Test_HTTP_Methods_(OTG-CONFIG-006)' 255 | 256 | only_if { HTTP_METHODS_CHECK != false } 257 | describe file(nginx_conf) do 258 | its('content') { should match(/^\s*if\s+\(\$request_method\s+!~\s+\^\(#{HTTP_METHODS}\)\$\)\{?$/) } 259 | end 260 | end 261 | 262 | control 'nginx-15' do 263 | impact 1.0 264 | title 'Content-Security-Policy' 265 | desc 'The Content-Security-Policy HTTP response header helps you reduce XSS risks on modern browsers by declaring what dynamic resources are allowed to load via a HTTP Header' 266 | describe parse_config(nginx_parsed_config, options_add_header) do 267 | its('add_header') { should include 'Content-Security-Policy "script-src \'self\'; object-src \'self\'"' } 268 | end 269 | end 270 | 271 | control 'nginx-16' do 272 | impact 1.0 273 | title 'Set cookie with HttpOnly and Secure flag' 274 | desc 'You can mitigate most of the common Cross Site Scripting attack using HttpOnly and Secure flag in a cookie. Without having HttpOnly and Secure, it is possible to steal or manipulate web application session and cookies and it’s dangerous.' 275 | only_if { NGINX_COOKIE_FLAG_MODULE != false } 276 | describe parse_config(nginx_parsed_config, options_add_header) do 277 | its('set_cookie_flag') { should include '* HttpOnly secure' } 278 | end 279 | end 280 | 281 | control 'nginx-17' do 282 | impact 1.0 283 | title 'Control timeouts to improve performance' 284 | desc 'Control timeouts to improve server performance and cut clients.' 285 | describe parse_config(nginx_parsed_config, options) do 286 | its('keepalive_timeout') { should eq KEEPALIVE_TIMEOUT } 287 | end 288 | describe parse_config(nginx_parsed_config, options) do 289 | its('client_body_timeout') { should eq CLIENT_BODY_TIMEOUT } 290 | end 291 | describe parse_config(nginx_parsed_config, options) do 292 | its('client_header_timeout') { should eq CLIENT_HEADER_TIMEOUT } 293 | end 294 | describe parse_config(nginx_parsed_config, options) do 295 | its('send_timeout') { should eq SEND_TIMEOUT } 296 | end 297 | end 298 | -------------------------------------------------------------------------------- /inspec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: nginx-baseline 3 | title: DevSec Nginx Baseline 4 | maintainer: DevSec Hardening Framework Team 5 | copyright: DevSec Hardening Framework Team 6 | copyright_email: hello@dev-sec.io 7 | license: Apache-2.0 8 | summary: Test-suite for best-practice nginx hardening 9 | inspec_version: '>= 4.6.3' 10 | version: 2.5.1 11 | supports: 12 | - os-family: unix 13 | -------------------------------------------------------------------------------- /libraries/nginx_lib.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Copyright:: 2016, Patrick Muench 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # author: Christoph Hartmann 18 | # author: Dominik Richter 19 | # author: Patrick Muench 20 | 21 | class Nginxlib < Inspec.resource(1) 22 | name 'nginx_lib' 23 | 24 | def valid_users 25 | # define nginx user for different distros 26 | 27 | centos_user = 'nginx' 28 | debian_user = 'www-data' 29 | web_user = debian_user 30 | 31 | # adjust the nginx user based on OS 32 | case inspec.os[:family] 33 | when 'ubuntu', 'debian' 34 | web_user 35 | when 'redhat', 'centos', 'fedora' 36 | web_user = centos_user 37 | end 38 | 39 | web_user 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":gitSignOff" 6 | ], 7 | "dependencyDashboard": true, 8 | "dependencyDashboardAutoclose": true, 9 | "packageRules": [ 10 | { 11 | "matchUpdateTypes": ["patch", "minor"], 12 | "automerge": true 13 | } 14 | ] 15 | } 16 | --------------------------------------------------------------------------------