Compare commits
62 Commits
nsm_c4po_3
...
main
Author | SHA1 | Date |
---|---|---|
|
661cbe580d | |
|
8114abe9b6 | |
|
1888a98e08 | |
|
a5fa8ca9dd | |
|
930306d00f | |
|
dee3c35180 | |
|
306ee25085 | |
|
7055b7caf5 | |
|
056e4532fa | |
|
b6ec78ef49 | |
|
2f6fd7c2bc | |
|
bc8d59f1a9 | |
|
cf7204fb9d | |
|
6e55e61ce5 | |
|
061b93ff5e | |
|
65985e5ef3 | |
|
ed7c70c62d | |
|
b4bf6de8f8 | |
|
e0e23f7383 | |
|
07c6871294 | |
|
9e4fa27b92 | |
|
2c7ac85f6e | |
|
9fddff7740 | |
|
a37e06f8ca | |
|
3be43fa96e | |
|
4ca2828e0f | |
|
79a2493c37 | |
|
bb544c71a0 | |
|
280948c470 | |
|
88b3647295 | |
|
3c3f005537 | |
|
e27d6005db | |
|
40224635ab | |
|
cc182d932b | |
|
f5e34722f5 | |
|
6f209dfbb4 | |
|
16bc1a5d4f | |
|
46f79dcf89 | |
|
6a625349c8 | |
|
27a8e963e9 | |
|
076fa087e8 | |
|
a4536e9735 | |
|
e9aec4ec3e | |
|
b2f430f9fd | |
|
84b7c1a07d | |
|
de659e3293 | |
|
c1293b4da1 | |
|
f658073bcf | |
|
5d89467c1e | |
|
747cade495 | |
|
6764583481 | |
|
ca7018cad9 | |
|
b695b17a9e | |
|
ecaaeea079 | |
|
d814a87033 | |
|
5894722633 | |
|
93ccf3e034 | |
|
6ae4d4e62d | |
|
2cbb2d522b | |
|
6ec16c0cbf | |
|
4a2024dd69 | |
|
24dccb3e8f |
|
@ -0,0 +1,106 @@
|
|||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# GitHub recommends pinning actions to a commit SHA.
|
||||
# To get a newer version, you will need to update the SHA.
|
||||
# You can also reference a tag or branch, but the action may change without warning.
|
||||
|
||||
name: "CI: Clean Build C4PO"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
|
||||
env:
|
||||
ANGULAR_PATH: security-c4po-angular
|
||||
API_PATH: security-c4po-api
|
||||
REPORTING_PATH: security-c4po-reporting
|
||||
CFG_PATH: security-c4po-cfg
|
||||
|
||||
ANGULAR_CLI_VERSION: 15
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
angular_job:
|
||||
name: "Angular Job"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Use Node.js 16.x"
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: "Install NPM dependencies"
|
||||
run: |
|
||||
cd $ANGULAR_PATH
|
||||
npm ci
|
||||
|
||||
- name: "Build assets"
|
||||
run: |
|
||||
cd $ANGULAR_PATH
|
||||
npm run build --if-present
|
||||
|
||||
- name: "Run tests"
|
||||
run: |
|
||||
cd $ANGULAR_PATH
|
||||
npm test
|
||||
|
||||
api_job:
|
||||
name: "API Job"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Set up JDK 11"
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: "Setup Gradle"
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-version: 6.5
|
||||
|
||||
- name: "Execute Gradle build"
|
||||
run: |
|
||||
cd $API_PATH
|
||||
./gradlew clean build -x dependencyCheckAnalyze
|
||||
|
||||
reporting_job:
|
||||
name: "Reporting Job"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Set up JDK 11"
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: "Setup Gradle"
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-version: 6.5
|
||||
|
||||
- name: "Execute Gradle build"
|
||||
run: |
|
||||
cd $REPORTING_PATH
|
||||
./gradlew clean build
|
|
@ -0,0 +1,173 @@
|
|||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
|
||||
# GitHub recommends pinning actions to a commit SHA.
|
||||
# To get a newer version, you will need to update the SHA.
|
||||
# You can also reference a tag or branch, but the action may change without warning.
|
||||
|
||||
name: "CD: Publish C4PO to Docker Hub"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
ANGULAR_PATH: security-c4po-angular
|
||||
API_PATH: security-c4po-api
|
||||
REPORTING_PATH: security-c4po-reporting
|
||||
CFG_PATH: security-c4po-cfg
|
||||
|
||||
jobs:
|
||||
|
||||
angular_job:
|
||||
name: "Angular Job"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Use Node.js 16.x"
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '16.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: "Install NPM dependencies"
|
||||
run: |
|
||||
cd $ANGULAR_PATH
|
||||
npm ci
|
||||
|
||||
- name: "Build assets"
|
||||
run: |
|
||||
cd $ANGULAR_PATH
|
||||
npm run build --if-present
|
||||
|
||||
- name: "Run tests"
|
||||
run: |
|
||||
cd $ANGULAR_PATH
|
||||
npm test
|
||||
|
||||
api_job:
|
||||
name: "API Job"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Set up JDK 11"
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: "Setup Gradle"
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-version: 6.5
|
||||
|
||||
- name: "Execute Gradle build"
|
||||
run: |
|
||||
cd $API_PATH
|
||||
./gradlew clean bootJar -x dependencyCheckAnalyze
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: API-jar
|
||||
path: security-c4po-api/build/libs/
|
||||
|
||||
reporting_job:
|
||||
name: "Reporting Job"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Set up JDK 11"
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: "Setup Gradle"
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
gradle-version: 6.5
|
||||
|
||||
- name: "Execute Gradle build"
|
||||
run: |
|
||||
cd $REPORTING_PATH
|
||||
./gradlew clean bootJar
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: REPORTING-jar
|
||||
path: security-c4po-reporting/build/libs/
|
||||
|
||||
push_c4po_to_docker_hub:
|
||||
name: "Push images to Docker Hub"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs: [angular_job, api_job, reporting_job]
|
||||
|
||||
steps:
|
||||
- name: "Check out the repo"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Log in to Docker Hub"
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: "Extract metadata (tags, labels) for Docker"
|
||||
id: meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
with:
|
||||
images: cellecram/security-c4po # my-docker-hub-namespace/my-docker-hub-repository
|
||||
|
||||
- name: Download jar api artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: API-jar
|
||||
path: security-c4po-api/build/libs/
|
||||
|
||||
- name: Download jar reporting artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: REPORTING-jar
|
||||
path: security-c4po-reporting/build/libs/
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@94ab11c41e45d028884a99163086648e898eed25 #v1
|
||||
|
||||
- name: "Buildx & Push Docker images for AMD64 & ARM64"
|
||||
run: |
|
||||
cd $CFG_PATH
|
||||
docker buildx build --push \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag cellecram/security-c4po:mongo ./c4po-db
|
||||
docker buildx build --push \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag cellecram/security-c4po:keycloak ./c4po-keycloak
|
||||
docker buildx build --push \
|
||||
--build-arg JAR_FILE_REPORT=./build/libs/security-c4po-reporting-0.0.1-SNAPSHOT.jar \
|
||||
--build-arg SPRING_PROFILES_ACTIVE=COMPOSE \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag cellecram/security-c4po:reporting ../security-c4po-reporting
|
||||
docker buildx build --push \
|
||||
--build-arg JAR_FILE_API=./build/libs/security-c4po-api-0.0.1-SNAPSHOT.jar \
|
||||
--build-arg SPRING_PROFILES_ACTIVE=COMPOSE \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag cellecram/security-c4po:api ../security-c4po-api
|
||||
docker buildx build --push \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag cellecram/security-c4po:angular ../security-c4po-angular
|
|
@ -0,0 +1,56 @@
|
|||
# Contributing to Security-C4PO
|
||||
|
||||
First off, thanks for taking the time to contribute! 👍
|
||||
|
||||
The following is a set of guidelines for contributing to this project and its packages, which are hosted on GitHub.
|
||||
These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
### Reporting Bugs
|
||||
This section guides you through submitting a bug report. Following these guidelines helps maintainers and the community understand your report.
|
||||
|
||||
Explain the problem and include additional details to help maintainers reproduce the problem:
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to identify the problem.
|
||||
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started the application, e.g. which command exactly you used in the terminal, or how you started the application otherwise. When listing steps, **don't just say what you did, but explain how you did it**.
|
||||
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
|
||||
* **Explain which behavior you expected to see instead and why.**
|
||||
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
|
||||
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened.
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion, including completely new features and minor improvements to existing functionality.
|
||||
Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.
|
||||
* **Use a clear and descriptive title** for the issue to identify the suggestion.
|
||||
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
* **Include screenshots, mock-ups or animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to.
|
||||
* **Explain why this enhancement would be useful**
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Use the following conventions:
|
||||
* Branch: `<initial>_c4po_<issuenumber>`
|
||||
* Commit: `feat: <What was implemented?>` or `fix: <What got fixed?>`
|
||||
By participating, you are expected to uphold this code.
|
||||
|
||||
## Local development
|
||||
Security-C4PO and all it's included micorservices can be developed locally.
|
||||
Execute `c4po-dev.sh` and all services will run on a dev server.
|
||||
|
||||
#### Testuser Credentials:
|
||||
* Username: c4po
|
||||
* Password: Test1234!
|
||||
|
||||
#### Technical Environment Requirements
|
||||
* Docker / Docker-compose
|
||||
* OpenJDK 11
|
||||
* Node 14.15.1 / npm 6.14.8
|
||||
|
||||
#### Helpfull Tools
|
||||
* mongoDB Compass
|
||||
* Postman
|
||||
|
||||
## Issue Board
|
||||
[C4PO Board](https://github.com/Marcel-Haag/security-c4po/projects/1)
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [2020] [Marcel Haag]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
97
README.md
97
README.md
|
@ -1,43 +1,94 @@
|
|||
# security-c4po
|
||||

|
||||

|
||||
[](https://owasp.org/other_projects/)<!-- @IGNORE PREVIOUS: link -->
|
||||
|
||||
### Chief Innovator
|
||||
> Daniel Mader
|
||||
|
||||
### Project Leads
|
||||
* Andreas Falk
|
||||
* Christina Paule
|
||||

|
||||
|
||||
### Developers
|
||||
* Marcel Haag
|
||||
* Norman Schmidt
|
||||
* Stipe Knez
|
||||
Welcome to the frontend repository of Security C4PO, an open-source pentest reporting tool.
|
||||
Security C4PO is a powerful, user-friendly tool designed to simplify the process of generating professional pentest reports.
|
||||
It aims to streamline and automate the often time-consuming task of creating comprehensive reports by providing an intuitive web-based interface that facilitates the content of the [OWASP TESTING GUIDE](https://owasp.org/www-project-web-security-testing-guide/v42/).
|
||||
|
||||
### Technical Requirements
|
||||
* Docker / Docker-compose
|
||||
* OpenJDK 11
|
||||
* Node 14.15.1 / npm 6.14.8
|
||||
* MongoDB 4.4.6
|
||||
This repository contains the codebase of Security C4PO, built with an Angular Frontend and two Spring Boot Backend Microservices.
|
||||
|
||||
### Tools
|
||||
* mongoDB Compass
|
||||
* Postman
|
||||
[](https://www.youtube.com/channel/UCDwRRDVepRUowI0NmBy_9lQ)
|
||||
|
||||
|
||||
## Table of Contents
|
||||
* [Docker Hub Setup](#docker-hub-setup)
|
||||
* [Application Architecture](#application-architecture)
|
||||
* [Data Structure](#data-structure)
|
||||
* [C4PO Roadmap](#c4po-roadmap)
|
||||
* [Project](#project)
|
||||
* [Technical Requirements](#technical-requirements)
|
||||
* [Tools](#tools)
|
||||
* [Conventions](#conventions)
|
||||
* [Development server](#development-server)
|
||||
* [Testuser Credentials](#testuser-credentials)
|
||||
* [Contributing](#contributing)
|
||||
* [License](#license)
|
||||
|
||||
## Docker Hub Setup
|
||||
[](https://hub.docker.com/repository/docker/cellecram/security-c4po/general)
|
||||
* Pull all images:
|
||||
* `docker image pull --all-tags cellecram/security-c4po`
|
||||
* Create network:
|
||||
* `docker network create -d bridge c4po`
|
||||
* Start images:
|
||||
* `docker run --network=c4po --name c4po-keycloak -d -p 8080:8080 cellecram/security-c4po:keycloak`
|
||||
* `docker run --network=c4po --name c4po-db -d -p 27017:27017 cellecram/security-c4po:mongo`
|
||||
* `docker run --network=c4po --name c4po-angular -d -p 4200:4200 cellecram/security-c4po:angular`
|
||||
* `docker run --network=c4po -e "SPRING_PROFILES_ACTIVE=COMPOSE" --name c4po-api -d -p 8443:8443 cellecram/security-c4po:api`
|
||||
* `docker run --network=c4po -e "SPRING_PROFILES_ACTIVE=COMPOSE" --name c4po-reporting -d -p 8444:8444 cellecram/security-c4po:reporting`
|
||||
|
||||
### OR: Run Script (Docker Hub)
|
||||
Execute `c4po-prod.sh` and all services will be pulled from Docker Hub and started.
|
||||
You can reach the application by entering http://localhost:4200 in you browser.
|
||||
|
||||
## Application Architecture
|
||||

|
||||
|
||||
## Data Structure
|
||||

|
||||
|
||||
## C4PO Roadmap
|
||||

|
||||
|
||||
## Project
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
### Technical Requirements
|
||||
* Docker / Docker-compose
|
||||
* OpenJDK 11
|
||||
* Node 16.20.2 / npm 8.19.4
|
||||
* MongoDB 4.4.6
|
||||
|
||||
### Tools
|
||||
* mongoDB Compass
|
||||
* Postman
|
||||
* Jaspersoft Studio
|
||||
|
||||
### Conventions
|
||||
* Branch: `<initial>_c4po_<issuenumber>`
|
||||
* Commit: `feat: <What was implemented?>` or `fix: <What got fixed?>`
|
||||
|
||||
### Development server
|
||||
Execute 'c4po.sh' and all services will run on a dev server.
|
||||
Execute `c4po-dev.sh` and all services will run on a dev server.
|
||||
You can reach the application by entering http://localhost:4200 in you browser.
|
||||
|
||||
### Testuser Credentials:
|
||||
* Username: ttt
|
||||
### Testuser Credentials
|
||||
* Username: c4po
|
||||
* Password: Test1234!
|
||||
|
||||
## C4PO Roadmap
|
||||

|
||||
## Contributing
|
||||
Contributions to Security C4PO are welcome! If you'd like to contribute to the project, please follow the guidelines outlined in the [CONTRIBUTING.md](https://github.com/marcel-haag/security-c4po/blob/main/CONTRIBUTING.md) file.
|
||||
|
||||
## License
|
||||
Security C4PO is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) License. Please see the [LICENSE](https://github.com/marcel-haag/security-c4po/blob/main/LICENSE.md) file for more information.
|
||||
|
||||
We hope you find Security C4PO useful for managing and generating pentest reports. If you encounter any issues or have suggestions for improvement, please feel free to create an issue on the [issue tracker](https://github.com/Marcel-Haag/security-c4po/issues).
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
## Dependency License Report for security-c4po SNAPSHOT
|
||||
|
||||
#### Example
|
||||
|
||||
1. Group: antlr Name: antlr Version: 2.7.7
|
||||
|
||||
POM Project URL: http://www.antlr.org/
|
||||
|
||||
POM License: BSD License - http://www.antlr.org/license.html
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
This report was generated at Thu Oct 01 09:28:53 CEST 2020.
|
|
@ -1,15 +1,5 @@
|
|||
#!/bin/bash
|
||||
baseDir=$(pwd)
|
||||
|
||||
composeDir=$baseDir"/security-c4po-cfg"
|
||||
keycloakVolume="security-c4po-cfg/volumes/keycloak/data/*"
|
||||
mongoVolume="security-c4po-cfg/volumes/mongodb/data/*"
|
||||
|
||||
composeKeycloak=$baseDir"/security-c4po-cfg/kc/docker-compose.keycloak.yml"
|
||||
composeDatabase=$baseDir"/security-c4po-cfg/mongodb/docker-compose.mongodb.yml"
|
||||
composeFrontend=$baseDir"/security-c4po-cfg/frontend/docker-compose.frontend.yml"
|
||||
composeBackend=$baseDir"/security-c4po-cfg/backend/docker-compose.backend.yml"
|
||||
|
||||
compose=$baseDir"/security-c4po-cfg/docker-compose.yml"
|
||||
|
||||
echo -e "
|
||||
|
@ -24,24 +14,29 @@ ______| |______ |_____ |_____| | \_ __|__ | | _/_/_/ _/
|
|||
|
||||
echo "-------------CLEAN UP Container---------------"
|
||||
echo -e "\n"
|
||||
rm -r ${keycloakVolume}
|
||||
docker rm -f c4po-keycloak
|
||||
docker rm -f c4po-keycloak-postgres
|
||||
docker rm -f c4po-db
|
||||
#docker rm -f c4po-keycloak ### toggle to clear keycloak with every start ###
|
||||
#docker rm -f c4po-db ### toggle to clear database with every start ###
|
||||
docker rm -f c4po-reporting
|
||||
docker rm -f c4po-api
|
||||
docker rm -f c4po-angular
|
||||
echo -e "\n"
|
||||
|
||||
echo "-----------------Start Build------------------"
|
||||
echo " - Report Engine: "
|
||||
docker-compose -f ${compose} build c4po-db
|
||||
echo " - Report Engine: "
|
||||
docker-compose -f ${compose} build c4po-keycloak
|
||||
echo -e "\n"
|
||||
echo " - Report Engine: "
|
||||
docker-compose -f ${compose} build c4po-reporting --build-arg JAR_FILE_REPORT=./build/libs/security-c4po-reporting-0.0.1-SNAPSHOT.jar ### toggle for additional build args ###
|
||||
echo -e "\n"
|
||||
echo " - Backend: "
|
||||
docker-compose -f ${composeBackend} build
|
||||
docker-compose -f ${compose} build c4po-api --build-arg JAR_FILE_API=./build/libs/security-c4po-api-0.0.1-SNAPSHOT.jar ### toggle for additional build args ###
|
||||
echo -e "\n"
|
||||
echo " - Frontend: "
|
||||
docker-compose -f ${composeFrontend} build
|
||||
docker-compose -f ${compose} build c4po-angular
|
||||
echo -e "\n"
|
||||
# docker-compose -f ${compose} up
|
||||
|
||||
echo "------------Start Docker Container------------"
|
||||
echo -e "\n"
|
||||
docker-compose -f ${composeKeycloak} -f ${composeDatabase} -f ${composeBackend} -f ${composeFrontend} up
|
||||
# docker-compose -f ${compose} up
|
||||
docker-compose -f ${compose} up
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
baseDir=$(pwd)
|
||||
compose=$baseDir"/security-c4po-cfg/docker-compose.yml"
|
||||
|
||||
echo -e "
|
||||
_______ _______ _______ _ _ ______ _____ _______ __ __
|
||||
|______ |______ | | | |_____/ | | \_/
|
||||
______| |______ |_____ |_____| | \_ __|__ | | _/_/_/ _/ _/ _/_/_/ _/_/
|
||||
_/ _/ _/ _/ _/ _/ _/
|
||||
_/ _/_/_/_/ _/_/_/ _/ _/
|
||||
_/ _/ _/ _/ _/
|
||||
_/_/_/ _/ _/ _/_/
|
||||
\n"
|
||||
|
||||
echo "---------------Pull C4PO from Docker Hub----------------"
|
||||
echo -e "\n"
|
||||
docker image pull --all-tags cellecram/security-c4po
|
||||
echo -e "\n"
|
||||
|
||||
echo "---------------Create Network----------------"
|
||||
echo -e "\n"
|
||||
docker network create -d bridge c4po
|
||||
echo -e "\n"
|
||||
|
||||
echo "---------------Start Containers---------------"
|
||||
echo -e "\n"
|
||||
docker run --network=c4po --name c4po-keycloak -d -p 8080:8080 cellecram/security-c4po:keycloak
|
||||
echo -e "\n"
|
||||
docker run --network=c4po --name c4po-db -d -p 27017:27017 cellecram/security-c4po:mongo
|
||||
echo -e "\n"
|
||||
docker run --network=c4po --name c4po-angular -d -p 4200:4200 cellecram/security-c4po:angular
|
||||
echo -e "\n"
|
||||
docker run --network=c4po -e "SPRING_PROFILES_ACTIVE=COMPOSE" --name c4po-api -d -p 8443:8443 cellecram/security-c4po:api
|
||||
echo -e "\n"
|
||||
docker run --network=c4po -e "SPRING_PROFILES_ACTIVE=COMPOSE" --name c4po-reporting -d -p 8444:8444 cellecram/security-c4po:reporting
|
|
@ -1,18 +0,0 @@
|
|||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
|
@ -44,3 +44,6 @@ testem.log
|
|||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Chache
|
||||
.angular/*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# base image
|
||||
FROM node:14.15.3
|
||||
FROM node:14
|
||||
|
||||
# set working directory
|
||||
WORKDIR /app
|
||||
|
@ -9,8 +9,8 @@ ENV PATH /app/node_modules/.bin:$PATH
|
|||
|
||||
# install and cache app dependencies
|
||||
COPY package.json /app/package.json
|
||||
RUN npm install
|
||||
RUN npm install -g @angular/cli@12.2.17
|
||||
RUN NODE_ENV=development npm install
|
||||
RUN NODE_ENV=development npm install -g @angular/cli@12.2.17
|
||||
|
||||
# add app
|
||||
COPY . /app
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# SecurityC4poAngular
|
||||
# Security C4PO Angular
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.0.
|
||||
This Angular application serves as the frontend interface for Security C4PO, allowing users to efficiently manage and generate comprehensive reports for their penetration testing activities.
|
||||
|
||||
## Development server
|
||||
|
||||
|
@ -16,12 +16,19 @@ Run `ng build` to build the project. The build artifacts will be stored in the `
|
|||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
Run `ng test` to execute the unit tests via [Jest](https://jestjs.io/).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
Run `ng e2e` to execute the end-to-end tests via [Cypress](https://www.cypress.io/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests are welcome. For major changes, please open an issue first
|
||||
to discuss what you would like to change.
|
||||
|
||||
Please make sure to read our [contributing guideline](https://github.com/marcel-haag/security-c4po/blob/main/CONTRIBUTING.md).
|
||||
|
|
|
@ -28,14 +28,21 @@
|
|||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/assets/@theme/styles/styles.scss"
|
||||
"src/assets/@theme/styles/styles.scss",
|
||||
"node_modules/@fortawesome/fontawesome-free/css/all.css",
|
||||
"node_modules/@glidejs/glide/src/assets/sass/glide.core.scss",
|
||||
"node_modules/@glidejs/glide/src/assets/sass/glide.theme.scss"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/@fortawesome/fontawesome-free/js/all.js"
|
||||
],
|
||||
"scripts": [],
|
||||
"allowedCommonJsDependencies": [
|
||||
"buffer",
|
||||
"crypto-js/hmac-sha256",
|
||||
"crypto-js/lib-typedarrays",
|
||||
"js-cookie",
|
||||
"chartjs-plugin-annotation",
|
||||
"chart.js",
|
||||
"deep-equal",
|
||||
"moment-timezone",
|
||||
"uuid"
|
||||
|
@ -65,17 +72,25 @@
|
|||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "3mb",
|
||||
"maximumError": "5mb"
|
||||
"maximumWarning": "5mb",
|
||||
"maximumError": "8mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb"
|
||||
}
|
||||
]
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": ""
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
|
@ -84,7 +99,7 @@
|
|||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "security-c4po-angular:build:production"
|
||||
"browserTarget": "security-c4po-angular:build:development"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -140,7 +155,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "security-c4po-angular",
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,62 +11,67 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^12.2.16",
|
||||
"@angular/cdk": "^12.2.7",
|
||||
"@angular/common": "^12.2.16",
|
||||
"@angular/compiler": "~12.2.16",
|
||||
"@angular/core": "~12.2.16",
|
||||
"@angular/flex-layout": "^11.0.0-beta.33",
|
||||
"@angular/forms": "~12.2.16",
|
||||
"@angular/localize": "^12.2.16",
|
||||
"@angular/platform-browser": "~12.2.16",
|
||||
"@angular/platform-browser-dynamic": "~12.2.16",
|
||||
"@angular/router": "~12.2.16",
|
||||
"@fortawesome/angular-fontawesome": "^0.8.2",
|
||||
"@angular/animations": "^15.2.10",
|
||||
"@angular/cdk": "^15.2.9",
|
||||
"@angular/common": "^15.2.10",
|
||||
"@angular/compiler": "^15.2.10",
|
||||
"@angular/core": "^15.2.10",
|
||||
"@angular/flex-layout": "^15.0.0-beta.42",
|
||||
"@angular/forms": "^15.2.10",
|
||||
"@angular/localize": "^15.2.10",
|
||||
"@angular/platform-browser": "^15.2.10",
|
||||
"@angular/platform-browser-dynamic": "^15.2.10",
|
||||
"@angular/router": "^15.2.10",
|
||||
"@fortawesome/angular-fontawesome": "^0.10.0",
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@nebular/eva-icons": "^8.0.0",
|
||||
"@nebular/theme": "^8.0.0",
|
||||
"@ngneat/until-destroy": "~8.0.4",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.3.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.3.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.3.0",
|
||||
"@glidejs/glide": "^3.6.0",
|
||||
"@nebular/eva-icons": "^11.0.1",
|
||||
"@nebular/theme": "^11.0.1",
|
||||
"@ngneat/until-destroy": "^9.2.3",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"@ngxs/storage-plugin": "^3.7.3",
|
||||
"@ngxs/store": "^3.7.3",
|
||||
"chart.js": "^4.2.1",
|
||||
"deep-equal": "^2.0.5",
|
||||
"eva-icons": "^1.1.3",
|
||||
"font-awesome": "^4.7.0",
|
||||
"i18n-iso-countries": "^6.8.0",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"keycloak-angular": "^8.4.0",
|
||||
"keycloak-js": "^13.0.1",
|
||||
"keycloak-angular": "^13.1.0",
|
||||
"keycloak-js": "^18.0.0",
|
||||
"moment": "^2.29.1",
|
||||
"moment-timezone": "latest",
|
||||
"ng-mocks": "^13.4.2",
|
||||
"ng-mocks": "^14.12.2",
|
||||
"ngx-glide": "^15.0.0",
|
||||
"ngx-moment": "^5.0.0",
|
||||
"ngx-take-until-destroy": "^5.4.0",
|
||||
"ngx-translate-testing": "^5.2.0",
|
||||
"ngx-translate-testing": "^6.0.0",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
"rxjs": "^6.6.7",
|
||||
"rxjs": "^7.8.0",
|
||||
"tslib": "^2.3.1",
|
||||
"uuid": "^8.3.1",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-builders/jest": "14.0.0",
|
||||
"@angular-devkit/build-angular": "~12.2.16",
|
||||
"@angular/cli": "^12.2.16",
|
||||
"@angular/compiler-cli": "~12.2.16",
|
||||
"@angular-builders/jest": "^15.0.0",
|
||||
"@angular-devkit/build-angular": "^15.2.11",
|
||||
"@angular/cli": "^15.2.11",
|
||||
"@angular/compiler-cli": "^15.2.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@briebug/jest-schematic": "^2.1.1",
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@schematics/angular": "^10.2.4",
|
||||
"@types/jest": "28.1.1",
|
||||
"@types/node": "^12.20.47",
|
||||
"@briebug/jest-schematic": "^3.0.0",
|
||||
"codelyzer": "^6.0.2",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jest": "28.1.1",
|
||||
"protractor": "~7.0.0",
|
||||
"protractor": "^7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.3.5"
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"webpack": "^5.0.0"
|
||||
|
|
|
@ -2,20 +2,31 @@ import { NgModule } from '@angular/core';
|
|||
import { Routes, RouterModule } from '@angular/router';
|
||||
import {HomeComponent} from './home/home.component';
|
||||
import {AuthGuardService} from '../shared/guards/auth-guard.service';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
|
||||
export const START_PAGE = 'projects';
|
||||
export const START_PAGE = Route.PROJECT_OVERVIEW;
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'home',
|
||||
path: Route.HOME,
|
||||
component: HomeComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'projects',
|
||||
path: Route.PROJECT_OVERVIEW,
|
||||
loadChildren: () => import('./project-overview').then(mod => mod.ProjectOverviewModule),
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: Route.OBJECTIVE_OVERVIEW,
|
||||
loadChildren: () => import('./project-overview/project').then(mod => mod.ProjectModule),
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: Route.PENTEST_OBJECTIVE,
|
||||
loadChildren: () => import('./pentest').then(mod => mod.PentestModule),
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
// ToDo: Remove after default Keycloak login mask got reworked
|
||||
/*{
|
||||
path: 'login',
|
||||
|
@ -27,7 +38,7 @@ const routes: Routes = [
|
|||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
imports: [RouterModule.forRoot(routes, {})],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
|
|
|
@ -9,6 +9,8 @@ import {SessionState, SessionStateModel} from '@shared/stores/session-state/sess
|
|||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
import {filter} from 'rxjs/operators';
|
||||
import {NbIconLibraries} from '@nebular/theme';
|
||||
import {FaIconLibrary} from '@fortawesome/angular-fontawesome';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
|
@ -24,6 +26,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
|
||||
constructor(private translateService: TranslateService,
|
||||
private store: Store,
|
||||
private iconLibraries: FaIconLibrary,
|
||||
private nebularIconLibraries: NbIconLibraries,
|
||||
@Inject(LOCALE_ID) private localeId: string) {
|
||||
this.initApp();
|
||||
}
|
||||
|
@ -44,10 +48,14 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
initApp(): void {
|
||||
// for global language
|
||||
this.translateService.use(this.localeId);
|
||||
|
||||
// for number, date and time
|
||||
registerLocaleData(localeDe, 'de-DE');
|
||||
|
||||
// for font-awesome icons
|
||||
this.nebularIconLibraries.registerFontPack('fas', { packClass: 'fas', iconClassPrefix: 'fa' });
|
||||
this.nebularIconLibraries.registerFontPack('far', { packClass: 'far', iconClassPrefix: 'fa' });
|
||||
this.nebularIconLibraries.registerFontPack('fab', { packClass: 'fab', iconClassPrefix: 'fa' });
|
||||
this.nebularIconLibraries.setDefaultPack('far');
|
||||
// for country codes
|
||||
this.setupCountryCode();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,30 +6,37 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
|||
import {
|
||||
NbLayoutModule,
|
||||
NbToastrModule,
|
||||
NbIconModule, NbCardModule, NbButtonModule, NbDialogService, NbDialogModule, NbSelectModule
|
||||
NbIconModule,
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
NbSelectModule,
|
||||
NbThemeModule,
|
||||
NbOverlayContainerAdapter,
|
||||
NbDialogModule, NbMenuModule, NbIconLibraries,
|
||||
} from '@nebular/theme';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {HttpLoaderFactory} from './common-app.module';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {FaConfig, FaIconLibrary, FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {fas} from '@fortawesome/free-solid-svg-icons';
|
||||
import {far} from '@fortawesome/free-regular-svg-icons';
|
||||
import {NgxsModule} from '@ngxs/store';
|
||||
import {SessionState} from '@shared/stores/session-state/session-state';
|
||||
import {environment} from '../environments/environment';
|
||||
import {NotificationService} from '@shared/services/notification.service';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {HeaderModule} from './header/header.module';
|
||||
import {HomeModule} from './home/home.module';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
import {httpInterceptorProviders} from '@shared/interceptors';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ConfirmDialogModule} from '@shared/modules/confirm-dialog/confirm-dialog.module';
|
||||
import {OverlayContainer} from '@angular/cdk/overlay';
|
||||
import {NgxsLoggerPluginModule} from '@shared/stores/plugins/store-logger-plugin';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {CustomOverlayContainer} from '@shared/modules/custom-overlay-container.component';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {RetryDialogModule} from '@shared/modules/retry-dialog/retry-dialog.module';
|
||||
import {FaConfig, FaIconLibrary, FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {fas} from '@fortawesome/free-solid-svg-icons';
|
||||
import {far} from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -40,16 +47,20 @@ import {ProjectState} from '@shared/stores/project-state/project-state';
|
|||
AppRoutingModule,
|
||||
RouterModule,
|
||||
NbLayoutModule,
|
||||
NbDialogModule.forRoot(),
|
||||
NbCardModule,
|
||||
NbIconModule,
|
||||
NbButtonModule,
|
||||
NbDialogModule.forRoot(),
|
||||
NbThemeModule.forRoot(),
|
||||
NbToastrModule.forRoot(), // used for notification service
|
||||
FlexLayoutModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
FontAwesomeModule,
|
||||
BrowserAnimationsModule,
|
||||
ThemeModule.forRoot(),
|
||||
NbMenuModule.forRoot(),
|
||||
NbSelectModule,
|
||||
ConfirmDialogModule,
|
||||
NgxsModule.forRoot([SessionState, ProjectState], {developmentMode: !environment.production}),
|
||||
NgxsLoggerPluginModule.forRoot({developmentMode: !environment.production}),
|
||||
HttpClientModule,
|
||||
|
@ -62,7 +73,7 @@ import {ProjectState} from '@shared/stores/project-state/project-state';
|
|||
}),
|
||||
HeaderModule,
|
||||
HomeModule,
|
||||
FlexLayoutModule
|
||||
RetryDialogModule
|
||||
],
|
||||
providers: [
|
||||
HttpClient,
|
||||
|
@ -72,21 +83,22 @@ import {ProjectState} from '@shared/stores/project-state/project-state';
|
|||
multi: true,
|
||||
deps: [KeycloakService]
|
||||
},
|
||||
OverlayContainer,
|
||||
KeycloakService,
|
||||
httpInterceptorProviders,
|
||||
NotificationService,
|
||||
DialogService,
|
||||
NbDialogService,
|
||||
{provide: NbOverlayContainerAdapter, useClass: CustomOverlayContainer}
|
||||
],
|
||||
bootstrap: [
|
||||
AppComponent
|
||||
]
|
||||
})
|
||||
export class AppModule {
|
||||
constructor(library: FaIconLibrary, faConfig: FaConfig) {
|
||||
library.addIconPacks(fas, far);
|
||||
constructor(library: FaIconLibrary, faConfig: FaConfig, libraries: NbIconLibraries) {
|
||||
library.addIconPacks(far, fas);
|
||||
libraries.registerFontPack('solid', {packClass: 'fas', iconClassPrefix: 'fa'});
|
||||
faConfig.defaultPrefix = 'fas';
|
||||
libraries.setDefaultPack('solid');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,22 +6,27 @@ import {HttpClient, HttpClientModule} from '@angular/common/http';
|
|||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {FlexLayoutModule, FlexModule} from '@angular/flex-layout';
|
||||
import {MomentModule} from 'ngx-moment';
|
||||
import {NotificationService} from '../shared/services/notification.service';
|
||||
import {NbToastrModule} from '@nebular/theme';
|
||||
import {ThemeModule} from '../assets/@theme/theme.module';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NbMenuModule, NbOverlayContainerAdapter, NbSpinnerModule, NbToastrModule} from '@nebular/theme';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
|
||||
|
||||
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
||||
return new TranslateHttpLoader(http);
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
declarations: [
|
||||
LoadingSpinnerComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NbToastrModule, // used for notification service
|
||||
NbSpinnerModule,
|
||||
FontAwesomeModule,
|
||||
FlexLayoutModule,
|
||||
ThemeModule.forRoot(),
|
||||
NbMenuModule.forRoot(),
|
||||
FlexModule,
|
||||
HttpClientModule,
|
||||
TranslateModule.forChild({
|
||||
|
@ -34,9 +39,11 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
|
|||
],
|
||||
providers: [
|
||||
HttpClient,
|
||||
NotificationService
|
||||
NotificationService,
|
||||
NbOverlayContainerAdapter
|
||||
],
|
||||
exports: [
|
||||
LoadingSpinnerComponent,
|
||||
// modules
|
||||
MomentModule
|
||||
]
|
||||
|
|
|
@ -2,35 +2,49 @@
|
|||
<img *ngIf="currentTheme === 'corporate', else changeImage"
|
||||
src="../../assets/images/favicons/favicon.ico" alt="logo dark" class="header-icon" width="60rem" height="60rem">
|
||||
<ng-template #changeImage>
|
||||
<img src="../../assets/images/favicons/corporate_favicon.ico" alt="logo light" class="header-icon" width="60rem" height="60rem">
|
||||
<img src="../../assets/images/favicons/favicon_corporate.ico" alt="logo light" class="header-icon" width="60rem"
|
||||
height="60rem">
|
||||
</ng-template>
|
||||
|
||||
<div class="logo-container">
|
||||
<h1 >{{SECURITYC4PO_TITLE}} </h1>
|
||||
<h1>{{SECURITYC4PO_TITLE}} </h1>
|
||||
</div>
|
||||
<div class="filler"></div>
|
||||
<div fxLayoutGap="4rem">
|
||||
<nb-actions size="medium">
|
||||
<nb-action class="toggle-theme">
|
||||
<button nbButton
|
||||
(click)="onClickSwitchTheme()">
|
||||
<fa-icon *ngIf="currentTheme === 'corporate', else changeIcon" [icon]="fa.faMoon"
|
||||
class="new-element-icon"></fa-icon>
|
||||
<!--Info Action-->
|
||||
<nb-action>
|
||||
<fa-icon title="Info" [icon]="fa.faCircleInfo" (click)="onClickShowTutorial()" class="action-element-icon fa-2x">
|
||||
</fa-icon>
|
||||
</nb-action>
|
||||
<!--OWASP Action-->
|
||||
<nb-action>
|
||||
<!-- Latest: https://owasp.org/www-project-web-security-testing-guide/latest/ -->
|
||||
<!-- Stable: https://owasp.org/www-project-web-security-testing-guide/stable/ -->
|
||||
<fa-icon title="OWASP Testing Guide"
|
||||
(click)="onClickGoToLink('https://owasp.org/www-project-web-security-testing-guide/v42/')"
|
||||
[icon]="fa.faFileInvoice" class="action-element-icon fa-2x">
|
||||
</fa-icon>
|
||||
</nb-action>
|
||||
<!--Theme Action-->
|
||||
<nb-action>
|
||||
<div (click)="onClickSwitchTheme()" class="action-element-icon">
|
||||
<fa-icon *ngIf="currentTheme === 'corporate', else changeIcon"
|
||||
title="Darktheme" [icon]="fa.faMoon" class="fa-2x">
|
||||
</fa-icon>
|
||||
<ng-template #changeIcon>
|
||||
<fa-icon [icon]="fa.faSun" class="new-element-icon"></fa-icon>
|
||||
<fa-icon title="Lighttheme" [icon]="fa.faSun" class="fa-2x"></fa-icon>
|
||||
</ng-template>
|
||||
</button>
|
||||
</div>
|
||||
</nb-action>
|
||||
<!--User Action-->
|
||||
<nb-action class="user-action">
|
||||
<nb-user [nbContextMenu]="userMenu"
|
||||
[picture]="FALLBACK_IMG"
|
||||
name="{{user?.getValue()?.username}}"
|
||||
title="Pentester">
|
||||
</nb-user>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
</div>
|
||||
<div *ngIf="selectedLanguage && languages" class="languageContainer">
|
||||
<nb-select selected="{{selectedLanguage}}" fullWidth>
|
||||
<nb-option *ngFor="let language of languages"
|
||||
value="{{language}}" (click)="onClickLanguage(language)" fxLayoutAlign="start center">
|
||||
<img src="../../assets/images/flags/{{language}}.svg" class="flag" width="25rem" height="16rem" alt="">
|
||||
<span fxFlexOffset="0.5rem"> {{'languageKeys.' + language | translate}} </span>
|
||||
</nb-option>
|
||||
</nb-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '~@nebular/theme/styles/global/breakpoints';
|
||||
@import '@nebular/theme/styles/global/breakpoints';
|
||||
@import "../../assets/@theme/styles/_variables.scss";
|
||||
|
||||
.header {
|
||||
|
@ -8,13 +8,26 @@
|
|||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.languageContainer {
|
||||
display: flex;
|
||||
max-width: 8rem;
|
||||
min-width: 8rem;
|
||||
.action-element-icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.owasp-redirect-button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.user-action {
|
||||
// width: 4rem;
|
||||
z-index: 10;
|
||||
// height: 3rem;
|
||||
.user-action-accordion-header {
|
||||
|
||||
.flag {
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,11 +42,6 @@
|
|||
align-items: center;
|
||||
width: auto;
|
||||
|
||||
.logo-container {
|
||||
font-style: oblique;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
nb-action {
|
||||
height: auto;
|
||||
display: flex;
|
||||
|
|
|
@ -3,17 +3,32 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
|
|||
import {HeaderComponent} from './header.component';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {FontAwesomeTestingModule} from '@fortawesome/angular-fontawesome/testing';
|
||||
import {NbActionsModule, NbSelectModule} from '@nebular/theme';
|
||||
import {NbActionsModule, NbMenuModule, NbMenuService, NbSelectModule} from '@nebular/theme';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
import {SESSION_STATE_NAME, SessionState, SessionStateModel} from '@shared/stores/session-state/session-state';
|
||||
import {User} from '@shared/models/user.model';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
|
||||
const DESIRED_STORE_STATE_SESSION: SessionStateModel = {
|
||||
userAccount: {
|
||||
...new User('ttt', 'test', 'user', 'default.user@test.de', 'en-US'),
|
||||
id: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
isAuthenticated: true
|
||||
};
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
let fixture: ComponentFixture<HeaderComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
|
@ -26,6 +41,7 @@ describe('HeaderComponent', () => {
|
|||
NbSelectModule,
|
||||
FontAwesomeTestingModule,
|
||||
HttpClientTestingModule,
|
||||
NbMenuModule,
|
||||
ThemeModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
|
@ -34,14 +50,24 @@ describe('HeaderComponent', () => {
|
|||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
RouterTestingModule.withRoutes([])
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([SessionState])
|
||||
],
|
||||
providers: [
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
NbMenuService,
|
||||
KeycloakService
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HeaderComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[SESSION_STATE_NAME]: DESIRED_STORE_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
|
|
@ -1,36 +1,141 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {NbThemeService} from '@nebular/theme';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {NbMenuItem, NbMenuService, NbThemeService} from '@nebular/theme';
|
||||
import {filter, map} from 'rxjs/operators';
|
||||
import {GlobalTitlesVariables} from '@shared/config/global-variables';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {ResetSession} from '@shared/stores/session-state/session-state.actions';
|
||||
import {UserService} from '@shared/services/user-service/user.service';
|
||||
import {User} from '@shared/models/user.model';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {Router} from '@angular/router';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ProfileSettingsComponent} from '@shared/modules/profile-settings/profile-settings.component';
|
||||
import {TutorialDialogComponent} from '@shared/modules/tutorial-dialog/tutorial-dialog.component';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss']
|
||||
})
|
||||
export class HeaderComponent implements OnInit{
|
||||
@UntilDestroy()
|
||||
export class HeaderComponent implements OnInit {
|
||||
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
readonly SECURITYC4PO_TITLE = GlobalTitlesVariables.SECURITYC4PO_TITLE;
|
||||
readonly SECURITYC4PO_TITLE: string = GlobalTitlesVariables.SECURITYC4PO_TITLE;
|
||||
// Menu only
|
||||
readonly settingsIcon = 'gear';
|
||||
readonly logoutIcon = 'right-from-bracket';
|
||||
|
||||
currentTheme = '';
|
||||
languages = ['en-US', 'de-DE'];
|
||||
selectedLanguage = '';
|
||||
|
||||
constructor(private themeService: NbThemeService, private translateService: TranslateService) { }
|
||||
user: BehaviorSubject<User> = new BehaviorSubject<User>(null);
|
||||
userMenu: NbMenuItem[] = [
|
||||
{
|
||||
title: 'settings',
|
||||
icon: { icon: this.settingsIcon, pack: 'fas' }
|
||||
},
|
||||
{
|
||||
title: 'logout',
|
||||
icon: { icon: this.logoutIcon, pack: 'fas'}
|
||||
}
|
||||
];
|
||||
readonly FALLBACK_IMG = 'assets/images/demo/anon-user-icon.png';
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private router: Router,
|
||||
private themeService: NbThemeService,
|
||||
private translateService: TranslateService,
|
||||
private dialogService: DialogService,
|
||||
private menuService: NbMenuService,
|
||||
private userService: UserService,
|
||||
protected keycloakService: KeycloakService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Handle theme selection
|
||||
this.themeService.onThemeChange()
|
||||
.pipe(
|
||||
map(({ name }) => name),
|
||||
map(({name}) => name),
|
||||
untilDestroyed(this),
|
||||
).subscribe(themeName => this.currentTheme = themeName);
|
||||
|
||||
// Load user profile
|
||||
this.userService.loadUserProfile().pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (user: User) => {
|
||||
this.user.next(user);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
// Handle user profile menu selection
|
||||
this.menuService.onItemClick()
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(themeName => this.currentTheme = themeName);
|
||||
this.selectedLanguage = this.translateService.currentLang;
|
||||
.subscribe((menuBag) => {
|
||||
// Makes sure that other menus without icon won't trigger
|
||||
if (menuBag.item.icon) {
|
||||
// tslint:disable-next-line:no-string-literal
|
||||
if (menuBag.item.icon['icon'] === this.settingsIcon) {
|
||||
this.dialogService.openCustomDialog(
|
||||
ProfileSettingsComponent,
|
||||
{
|
||||
user: this.user.getValue(),
|
||||
}
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
console.info('New Settings confirmed');
|
||||
}
|
||||
});
|
||||
}
|
||||
// tslint:disable-next-line:no-string-literal
|
||||
else if (menuBag.item.icon['icon'] === this.logoutIcon) {
|
||||
this.onClickLogOut();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Setup stream to translate menu item
|
||||
this.translateService.stream('global.action.profile')
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe((text: string) => {
|
||||
this.userMenu[0].title = text;
|
||||
});
|
||||
// Setup stream to translate menu item
|
||||
this.translateService.stream('global.action.logout')
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe((text: string) => {
|
||||
this.userMenu[1].title = text;
|
||||
});
|
||||
}
|
||||
|
||||
// HTML only
|
||||
onClickGoToLink(url: string): void {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
onClickShowTutorial(): void {
|
||||
this.dialogService.openCustomDialog(
|
||||
TutorialDialogComponent,
|
||||
{}
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
untilDestroyed(this)
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
onClickSwitchTheme(): void {
|
||||
|
@ -41,7 +146,19 @@ export class HeaderComponent implements OnInit{
|
|||
}
|
||||
}
|
||||
|
||||
onClickLanguage(language: string): void {
|
||||
this.translateService.use(language);
|
||||
onClickLogOut(): void {
|
||||
this.userService.logout().then(() => {
|
||||
console.warn('logout success');
|
||||
// Route user back to default page
|
||||
this.router.navigate([Route.HOME]).then(() => {
|
||||
// Reset User props from store
|
||||
this.keycloakService.clearToken();
|
||||
this.store.dispatch(new ResetSession());
|
||||
}, err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {HeaderComponent} from './header.component';
|
||||
import {NbActionsModule, NbButtonModule, NbCardModule, NbSelectModule} from '@nebular/theme';
|
||||
import {
|
||||
NbActionsModule,
|
||||
NbButtonModule,
|
||||
NbCardModule,
|
||||
NbContextMenuModule,
|
||||
NbSelectModule,
|
||||
NbUserModule
|
||||
} from '@nebular/theme';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {ProfileSettingsModule} from '@shared/modules/profile-settings/profile-settings.module';
|
||||
import {TutorialDialogModule} from '@shared/modules/tutorial-dialog/tutorial-dialog.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -13,16 +22,22 @@ import {TranslateModule} from '@ngx-translate/core';
|
|||
exports: [
|
||||
HeaderComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NbButtonModule,
|
||||
FontAwesomeModule,
|
||||
NbCardModule,
|
||||
NbActionsModule,
|
||||
FlexLayoutModule,
|
||||
NbSelectModule,
|
||||
TranslateModule
|
||||
]
|
||||
imports: [
|
||||
CommonModule,
|
||||
NbButtonModule,
|
||||
FontAwesomeModule,
|
||||
NbCardModule,
|
||||
NbActionsModule,
|
||||
FlexLayoutModule,
|
||||
NbSelectModule,
|
||||
TranslateModule,
|
||||
NbUserModule,
|
||||
NbContextMenuModule,
|
||||
ProfileSettingsModule,
|
||||
TutorialDialogModule
|
||||
],
|
||||
providers: [
|
||||
]
|
||||
})
|
||||
export class HeaderModule {
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '~@nebular/theme/styles/theming';
|
||||
@import '@nebular/theme/styles/theming';
|
||||
|
||||
$login-width: 24em;
|
||||
$input-width: 16rem;
|
||||
|
|
|
@ -21,8 +21,8 @@ import {ReactiveFormsModule} from '@angular/forms';
|
|||
import {User} from '../../shared/models/user.model';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {NotificationService} from '../../shared/services/notification.service';
|
||||
import {NotificationServiceMock} from '../../shared/services/notification.service.mock';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
|
||||
const DESIRED_STORE_STATE_SESSION: SessionStateModel = {
|
||||
|
@ -81,7 +81,6 @@ describe('LoginComponent', () => {
|
|||
...store.snapshot(),
|
||||
[SESSION_STATE_NAME]: DESIRED_STORE_STATE_SESSION
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {AbstractControl, FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||
import {AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms';
|
||||
import {Router} from '@angular/router';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {NotificationService, PopupType} from '../../shared/services/notification.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {User} from '../../shared/models/user.model';
|
||||
import {throwError} from 'rxjs';
|
||||
|
@ -22,7 +22,6 @@ import {KeycloakService} from 'keycloak-angular';
|
|||
export class LoginComponent implements OnInit {
|
||||
readonly MIN_LENGTH: number = 2;
|
||||
readonly SECURITYC4PO_TITLE = GlobalTitlesVariables.SECURITYC4PO_TITLE;
|
||||
readonly NOVATEC_NAME = GlobalTitlesVariables.NOVATEC_NAME;
|
||||
|
||||
// ToDo: Remove after adding real authentication
|
||||
private readonly user = new User('ttt', 'test', 'user', 'default.user@test.de', 'en-US');
|
||||
|
@ -30,7 +29,7 @@ export class LoginComponent implements OnInit {
|
|||
version: string;
|
||||
|
||||
// form control elements
|
||||
loginFormGroup: FormGroup;
|
||||
loginFormGroup: UntypedFormGroup;
|
||||
loginUsernameCtrl: AbstractControl;
|
||||
loginPasswordCtrl: AbstractControl;
|
||||
|
||||
|
@ -40,7 +39,7 @@ export class LoginComponent implements OnInit {
|
|||
|
||||
formCtrlStatus = FieldStatus.BASIC;
|
||||
|
||||
constructor(private fb: FormBuilder,
|
||||
constructor(private fb: UntypedFormBuilder,
|
||||
private router: Router,
|
||||
private store: Store,
|
||||
private readonly httpClient: HttpClient,
|
||||
|
|
|
@ -4,7 +4,7 @@ import {LoginComponent} from './login.component';
|
|||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {NotificationService} from '../../shared/services/notification.service';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {LoginRoutingModule} from './login-routing.module';
|
||||
import {NbButtonModule, NbCardModule, NbFormFieldModule, NbInputModule, NbLayoutModule} from '@nebular/theme';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
export {ObjectiveOverviewModule} from './objective-overview.module';
|
||||
export {ObjectiveOverviewRoutingModule} from './objective-overview-routing.module';
|
|
@ -0,0 +1,5 @@
|
|||
<div class="pentest-categories">
|
||||
<nb-menu id="category-menu" class="menu-style" tag="menu" [items]="categories"></nb-menu>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
@import '../../../assets/@theme/styles/themes';
|
||||
|
||||
.pentest-categories {
|
||||
width: 22vw;
|
||||
width: 20rem;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PentestCategoriesComponent } from './pentest-categories.component';
|
||||
import { ObjectiveCategoriesComponent } from './objective-categories.component';
|
||||
import {NbMenuModule, NbMenuService} from '@nebular/theme';
|
||||
import {NgxsModule} from '@ngxs/store';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
|
@ -13,14 +13,14 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
|||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
|
||||
describe('PentestCategoriesComponent', () => {
|
||||
let component: PentestCategoriesComponent;
|
||||
let fixture: ComponentFixture<PentestCategoriesComponent>;
|
||||
describe('ObjectiveCategoriesComponent', () => {
|
||||
let component: ObjectiveCategoriesComponent;
|
||||
let fixture: ComponentFixture<ObjectiveCategoriesComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
PentestCategoriesComponent
|
||||
ObjectiveCategoriesComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
@ -47,7 +47,7 @@ describe('PentestCategoriesComponent', () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestCategoriesComponent);
|
||||
fixture = TestBed.createComponent(ObjectiveCategoriesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
|
@ -1,23 +1,22 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {NbMenuItem, NbMenuService} from '@nebular/theme';
|
||||
import {Subject} from 'rxjs';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {ChangeCategory} from '@shared/stores/project-state/project-state.actions';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pentest-categories',
|
||||
templateUrl: './pentest-categories.component.html',
|
||||
styleUrls: ['./pentest-categories.component.scss']
|
||||
selector: 'app-objective-categories',
|
||||
templateUrl: './objective-categories.component.html',
|
||||
styleUrls: ['./objective-categories.component.scss']
|
||||
})
|
||||
export class PentestCategoriesComponent implements OnInit, OnDestroy {
|
||||
@UntilDestroy()
|
||||
export class ObjectiveCategoriesComponent implements OnInit {
|
||||
categories: NbMenuItem[] = [];
|
||||
selectedCategory: Category = 0;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(private store: Store,
|
||||
private menuService: NbMenuService,
|
||||
private translateService: TranslateService) {
|
||||
|
@ -25,22 +24,38 @@ export class PentestCategoriesComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit(): void {
|
||||
this.initTranslation();
|
||||
// Set first item in list as selected
|
||||
this.categories[0].selected = true;
|
||||
this.store.select(ProjectState.selectedCategory).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (categoryIndex) => {
|
||||
if (categoryIndex) {
|
||||
this.selectedCategory = categoryIndex;
|
||||
this.categories[categoryIndex].selected = true;
|
||||
} else {
|
||||
// Set first item in list as selected
|
||||
this.categories[0].selected = true;
|
||||
}
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
this.menuService.onItemClick()
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((menuBag) => {
|
||||
this.selectedCategory = menuBag.item.data;
|
||||
this.categories.forEach(category => {
|
||||
category.selected = false;
|
||||
});
|
||||
menuBag.item.selected = true;
|
||||
this.store.dispatch(new ChangeCategory(this.selectedCategory));
|
||||
if (menuBag.tag === 'menu') {
|
||||
this.selectedCategory = menuBag.item.data;
|
||||
this.categories.forEach(category => {
|
||||
category.selected = false;
|
||||
});
|
||||
if (this.selectedCategory >= 0) {
|
||||
menuBag.item.selected = true;
|
||||
this.store.dispatch(new ChangeCategory(this.selectedCategory));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private initTranslation(): void {
|
||||
|
@ -69,9 +84,4 @@ export class PentestCategoriesComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<div class="pentest-header" fxLayout="row" fxLayoutGap="2rem" fxLayoutAlign="space-between center">
|
||||
<div class="back-button-container">
|
||||
<button nbButton
|
||||
shape="round"
|
||||
title="{{ 'global.action.return' | translate }}"
|
||||
(click)="onClickRouteBack()">
|
||||
<fa-icon [icon]="fa.faLongArrowAltLeft"
|
||||
class="back-element-icon fa-lg"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="header-info" fxLayout="row" fxLayoutGap="4rem" fxLayoutAlign="space-between center">
|
||||
<app-report-state-tag class="state-tag"
|
||||
[currentReportState]="selectedProject$.getValue()?.state"></app-report-state-tag>
|
||||
<h4 class="project-title">{{selectedProject$.getValue().title}}</h4>
|
||||
<app-version-tag [version]="selectedProject$.getValue().version"></app-version-tag>
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<!--Actions for normal view-->
|
||||
<nb-actions size="medium" fxHide.lt-lg>
|
||||
<nb-action>
|
||||
<button nbButton
|
||||
status="primary"
|
||||
shape="round"
|
||||
(click)="onClickEditPentestProject()">
|
||||
<fa-icon [icon]="fa.faEdit"
|
||||
class="element-icon fa-lg"></fa-icon>
|
||||
</button>
|
||||
</nb-action>
|
||||
<nb-action>
|
||||
<button nbButton hero
|
||||
status="info"
|
||||
shape="round"
|
||||
(click)="onClickGeneratePentestReport()">
|
||||
<fa-icon [icon]="fa.faFileAlt"
|
||||
class="element-icon fa-lg"></fa-icon>
|
||||
<span class="element-text">{{ 'global.action.report' | translate }}</span>
|
||||
</button>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
<!--Actions for mobile devices-->
|
||||
<nb-actions size="medium" fxHide fxShow.lt-lg>
|
||||
<nb-action>
|
||||
<nb-user [nbContextMenu]="objectiveActionItems" shape="rectangle" [picture]="BARS_IMG" name="" [onlyPicture]></nb-user>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,37 @@
|
|||
@import '../../../assets/@theme/styles/_text-overflow.scss';
|
||||
|
||||
.pentest-header {
|
||||
width: 100vw;
|
||||
|
||||
.back-button-container {
|
||||
.back-element-icon {
|
||||
}
|
||||
}
|
||||
|
||||
.header-info {
|
||||
position: absolute;
|
||||
margin-left: 10rem;
|
||||
margin-right: 10rem;
|
||||
text-align: center;
|
||||
|
||||
.state-tag {
|
||||
}
|
||||
|
||||
.project-title {
|
||||
@include multiLineEllipsis($font-size: 1.5rem, $font-weight: bold, $line-height: 2rem, $lines-to-show: 1, $max-width: 36rem);
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
position: absolute;
|
||||
right: 2rem;
|
||||
|
||||
.element-icon {
|
||||
}
|
||||
|
||||
.element-text {
|
||||
padding-left: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ObjectiveHeaderComponent} from './objective-header.component';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {NbActionsModule, NbIconModule, NbMenuService} from '@nebular/theme';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {ProjectServiceMock} from '@shared/services/api/project.service.mock';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {ExportReportDialogService} from '@shared/modules/export-report-dialog/service/export-report-dialog.service';
|
||||
import {ExportReportDialogServiceMock} from '@shared/modules/export-report-dialog/service/export-report-dialog.service.mock';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: [],
|
||||
commentIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112']
|
||||
},
|
||||
};
|
||||
|
||||
describe('ObjectiveHeaderComponent', () => {
|
||||
let component: ObjectiveHeaderComponent;
|
||||
let fixture: ComponentFixture<ObjectiveHeaderComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ObjectiveHeaderComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
ThemeModule.forRoot(),
|
||||
FontAwesomeModule,
|
||||
NbIconModule,
|
||||
NbActionsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
NbMenuService,
|
||||
{provide: ProjectService, useValue: new ProjectServiceMock()},
|
||||
{provide: ProjectDialogService, useClass: ProjectDialogServiceMock},
|
||||
{provide: ExportReportDialogService, useClass: ExportReportDialogServiceMock},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ObjectiveHeaderComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,176 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {Router} from '@angular/router';
|
||||
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Project, ProjectDialogBody} from '@shared/models/project.model';
|
||||
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
|
||||
import {filter, mergeMap} from 'rxjs/operators';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {InitProjectState} from '@shared/stores/project-state/project-state.actions';
|
||||
import {ExportReportDialogService} from '@shared/modules/export-report-dialog/service/export-report-dialog.service';
|
||||
import {ExportReportDialogComponent} from '@shared/modules/export-report-dialog/export-report-dialog.component';
|
||||
import {NbMenuItem} from '@nebular/theme/components/menu/menu.service';
|
||||
import {NbMenuService} from '@nebular/theme';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-objective-header',
|
||||
templateUrl: './objective-header.component.html',
|
||||
styleUrls: ['./objective-header.component.scss']
|
||||
})
|
||||
export class ObjectiveHeaderComponent implements OnInit {
|
||||
|
||||
selectedProject$: BehaviorSubject<Project> = new BehaviorSubject<Project>(null);
|
||||
// Menu only
|
||||
readonly editIcon = 'edit';
|
||||
readonly fileExportIcon = 'file-export';
|
||||
// Mobile menu properties
|
||||
objectiveActionItems: NbMenuItem[] = [
|
||||
{
|
||||
title: 'global.action.edit',
|
||||
icon: { icon: this.editIcon, pack: 'fas' }
|
||||
},
|
||||
{
|
||||
title: 'global.action.report',
|
||||
icon: { icon: this.fileExportIcon, pack: 'fas' }
|
||||
},
|
||||
];
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
readonly BARS_IMG = 'assets/images/icons/bars.svg';
|
||||
readonly ELLIPSIS_IMG = 'assets/images/icons/ellipsis.svg';
|
||||
|
||||
constructor(private store: Store,
|
||||
private readonly notificationService: NotificationService,
|
||||
private dialogService: DialogService,
|
||||
private projectDialogService: ProjectDialogService,
|
||||
private projectService: ProjectService,
|
||||
private exportReportDialogService: ExportReportDialogService,
|
||||
private readonly router: Router,
|
||||
private translateService: TranslateService,
|
||||
private menuService: NbMenuService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.select(ProjectState.project).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedProject: Project) => {
|
||||
if (selectedProject) {
|
||||
this.selectedProject$.next(selectedProject);
|
||||
} else {
|
||||
this.router.navigate([Route.PROJECT_OVERVIEW]);
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle user profile menu action selection
|
||||
this.menuService.onItemClick()
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((menuBag) => {
|
||||
// Makes sure that other menus without icon won't trigger
|
||||
if (menuBag.item.icon) {
|
||||
// tslint:disable-next-line:no-string-literal
|
||||
if (menuBag.item.icon['icon'] === this.editIcon) {
|
||||
this.onClickEditPentestProject();
|
||||
}
|
||||
// tslint:disable-next-line:no-string-literal
|
||||
else if (menuBag.item.icon['icon'] === this.fileExportIcon) {
|
||||
this.onClickGeneratePentestReport();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Setup stream to translate menu action item
|
||||
this.translateService.stream('global.action.edit')
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe((text: string) => {
|
||||
this.objectiveActionItems[0].title = text;
|
||||
});
|
||||
// Setup stream to translate menu action item
|
||||
this.translateService.stream('global.action.report')
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe((text: string) => {
|
||||
this.objectiveActionItems[1].title = text;
|
||||
});
|
||||
}
|
||||
|
||||
onClickRouteBack(): void {
|
||||
this.router.navigate([Route.PROJECT_OVERVIEW])
|
||||
.then(
|
||||
() => this.store.reset({
|
||||
...this.store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: undefined
|
||||
})
|
||||
).finally();
|
||||
}
|
||||
|
||||
onClickEditPentestProject(): void {
|
||||
this.projectDialogService.openProjectDialog(
|
||||
ProjectDialogComponent,
|
||||
this.selectedProject$.getValue(),
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (project) => {
|
||||
if (project) {
|
||||
this.store.dispatch(new InitProjectState(
|
||||
project,
|
||||
[],
|
||||
[]
|
||||
)).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickGeneratePentestReport(): void {
|
||||
this.exportReportDialogService.openExportReportDialog(
|
||||
ExportReportDialogComponent,
|
||||
this.selectedProject$.getValue(),
|
||||
{
|
||||
closeOnEsc: true,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: true
|
||||
}
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
/*ToDo: Needed?*/
|
||||
/*mergeMap((value: ProjectDialogBody) => this.projectService.updateProject(this.selectedProject$.getValue().id, value)),*/
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
// ToDo: Open report in new Tab or just download it?
|
||||
// this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
// this.notificationService.showPopup('project.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,17 +1,12 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {PentestComponent} from './pentest.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: PentestComponent
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PentestRoutingModule {
|
||||
export class ObjectiveOverviewRoutingModule {
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {ObjectiveHeaderComponent} from './objective-header/objective-header.component';
|
||||
import {ObjectiveCategoriesComponent} from './objective-categories/objective-categories.component';
|
||||
import {ObjectiveTableComponent} from './objective-table/objective-table.component';
|
||||
import {
|
||||
NbCardModule,
|
||||
NbLayoutModule,
|
||||
NbTreeGridModule,
|
||||
NbMenuModule,
|
||||
NbListModule,
|
||||
NbButtonModule,
|
||||
NbTooltipModule,
|
||||
NbActionsModule, NbUserModule, NbContextMenuModule, NbSortDirective
|
||||
} from '@nebular/theme';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
|
||||
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {CommonAppModule} from '../common-app.module';
|
||||
import {ObjectiveOverviewRoutingModule} from './objective-overview-routing.module';
|
||||
import {ExportReportDialogModule} from '@shared/modules/export-report-dialog/export-report-dialog.module';
|
||||
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
|
||||
import {CommentWidgetModule} from '@shared/widgets/comment-widget/comment-widget.module';
|
||||
import {ReportStateTagModule} from '@shared/widgets/report-state-tag/report-state-tag.module';
|
||||
import {VersionTagModule} from '@shared/widgets/version-tag/version-tag.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ObjectiveHeaderComponent,
|
||||
ObjectiveCategoriesComponent,
|
||||
ObjectiveTableComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CommonAppModule,
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
// nbTooltip crashes app right now if used in component,
|
||||
// workaround: use title in html for now
|
||||
NbTooltipModule,
|
||||
NbTreeGridModule,
|
||||
TranslateModule,
|
||||
StatusTagModule,
|
||||
RouterModule,
|
||||
FormsModule,
|
||||
NbListModule,
|
||||
FontAwesomeModule,
|
||||
FlexLayoutModule,
|
||||
NbActionsModule,
|
||||
ExportReportDialogModule,
|
||||
ProjectDialogModule,
|
||||
ObjectiveOverviewRoutingModule,
|
||||
// Table Widgets
|
||||
FindigWidgetModule,
|
||||
CommentWidgetModule,
|
||||
NbMenuModule,
|
||||
ReportStateTagModule,
|
||||
VersionTagModule,
|
||||
NbUserModule,
|
||||
NbContextMenuModule
|
||||
],
|
||||
exports: [
|
||||
ObjectiveHeaderComponent,
|
||||
ObjectiveCategoriesComponent,
|
||||
ObjectiveTableComponent
|
||||
],
|
||||
providers: [
|
||||
NbSortDirective
|
||||
]
|
||||
})
|
||||
export class ObjectiveOverviewModule {
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<div class="pentest-table">
|
||||
<table [nbTreeGrid]="dataSource">
|
||||
<!--ToDo: Add the click event to every td manually except the actions column actions-->
|
||||
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
|
||||
<tr nbTreeGridRow *nbTreeGridRowDef="let pentest; columns: columns"
|
||||
class="pentest-cell"
|
||||
[ngClass]="{'disabled-objective' : !pentest.data['enabled']}">
|
||||
</tr>
|
||||
<!-- Test ID -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.testId' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest" (click)="onClickRouteToObjectivePentest(pentest.data)">
|
||||
<!-- Opens sub categories if row needs to be extendend -->
|
||||
<nb-tree-grid-row-toggle
|
||||
[expanded]="pentest.expanded"
|
||||
*ngIf="pentest.data?.childEntries?.length > 0">
|
||||
</nb-tree-grid-row-toggle>
|
||||
<!---->
|
||||
{{pentest.data['refNumber'] || '-'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Title -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.title' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest" (click)="onClickRouteToObjectivePentest(pentest.data)">
|
||||
{{ getTitle(pentest.data['refNumber']) | translate }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Status -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.status' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest" (click)="onClickRouteToObjectivePentest(pentest.data)">
|
||||
<app-status-tag [currentStatus]="pentest.data['status']"></app-status-tag>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Findings -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.findings&comments' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest" (click)="onClickRouteToObjectivePentest(pentest.data)">
|
||||
<div fxLayout="row" fxLayoutGap="0.5rem" fxLayoutAlign="center center">
|
||||
<app-findig-widget [numberOfFindings]="pentest.data['findingIds'] ? pentest.data['findingIds'].length : 0"></app-findig-widget>
|
||||
<span> / </span>
|
||||
<app-comment-widget [numberOfComments]="pentest.data['commentIds'] ? pentest.data['commentIds'].length : 0"></app-comment-widget>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Actions -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[4]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
||||
{{'global.actions' | translate}}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest" class="cell-actions">
|
||||
<div fxLayoutAlign="center center">
|
||||
<ng-container *ngIf="pentest.data['enabled'] === true; else renderDisablePentestButton">
|
||||
<button
|
||||
nbButton
|
||||
status="danger"
|
||||
size="small"
|
||||
shape="round"
|
||||
title="{{ 'global.action.disable' | translate }}"
|
||||
[disabled]="!pentest.data['id']"
|
||||
(click)="onClickDisableOrEnableObjective(pentest)">
|
||||
<fa-icon [icon]="fa.faBan"></fa-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
<ng-template #renderDisablePentestButton>
|
||||
<button
|
||||
nbButton
|
||||
status="control"
|
||||
size="small"
|
||||
shape="round"
|
||||
title="{{ 'global.action.enable' | translate }}"
|
||||
[disabled]="!pentest.data['id']"
|
||||
(click)="onClickDisableOrEnableObjective(pentest)">
|
||||
<fa-icon [icon]="fa.faCheck"></fa-icon>
|
||||
</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>
|
|
@ -0,0 +1,31 @@
|
|||
@import '../../../assets/@theme/styles/themes';
|
||||
|
||||
.pentest-table {
|
||||
// width: calc(78vw - 18%);
|
||||
// width: 100%;
|
||||
// width: calc(100% - 20rem);
|
||||
margin-right: 2rem;
|
||||
padding-right: 2rem;
|
||||
|
||||
.pentest-cell {
|
||||
// Add style here
|
||||
}
|
||||
|
||||
.pentest-cell:hover {
|
||||
cursor: pointer;
|
||||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
}
|
||||
|
||||
.disabled-objective {
|
||||
background-color: nb-theme(color-control-transparent-disabled);
|
||||
}
|
||||
|
||||
.disabled-objective:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
width: max-content;
|
||||
max-width: 180px;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {PentestTableComponent} from './pentest-table.component';
|
||||
import {ObjectiveTableComponent} from './objective-table.component';
|
||||
import {NbCardModule, NbTreeGridModule} from '@nebular/theme';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
|
@ -14,15 +14,19 @@ import {MockComponent} from 'ng-mocks';
|
|||
import {NgxsModule} from '@ngxs/store';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
|
||||
describe('PentestTableComponent', () => {
|
||||
let component: PentestTableComponent;
|
||||
let fixture: ComponentFixture<PentestTableComponent>;
|
||||
describe('ObjectiveTableComponent', () => {
|
||||
let component: ObjectiveTableComponent;
|
||||
let fixture: ComponentFixture<ObjectiveTableComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
PentestTableComponent,
|
||||
ObjectiveTableComponent,
|
||||
MockComponent(StatusTagComponent),
|
||||
MockComponent(FindigWidgetComponent)
|
||||
],
|
||||
|
@ -41,13 +45,17 @@ describe('PentestTableComponent', () => {
|
|||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NotificationService, useClass: NotificationServiceMock}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestTableComponent);
|
||||
fixture = TestBed.createComponent(ObjectiveTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
|
@ -0,0 +1,192 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import {ObjectiveEntry, Pentest, transformPentestsToObjectiveEntries} from '@shared/models/pentest.model';
|
||||
import {PentestService} from '@shared/services/api/pentest.service';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {catchError, filter, switchMap, tap} from 'rxjs/operators';
|
||||
import {BehaviorSubject, Observable, of} from 'rxjs';
|
||||
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
|
||||
import {Router} from '@angular/router';
|
||||
import {ChangePentest} from '@shared/stores/project-state/project-state.actions';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
import {sortDescending} from '@shared/functions/sort-names.function';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-objective-table',
|
||||
templateUrl: './objective-table.component.html',
|
||||
styleUrls: ['./objective-table.component.scss']
|
||||
})
|
||||
export class ObjectiveTableComponent implements OnInit {
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
|
||||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
columns: Array<ObjectiveColumns> = [
|
||||
ObjectiveColumns.TEST_ID,
|
||||
ObjectiveColumns.TITLE,
|
||||
ObjectiveColumns.STATUS,
|
||||
ObjectiveColumns.FINDINGS_AND_COMMENTS,
|
||||
ObjectiveColumns.ACTIONS
|
||||
];
|
||||
dataSource: NbTreeGridDataSource<ObjectiveEntry>;
|
||||
|
||||
private data: ObjectiveEntry[] = [];
|
||||
private pentests$: BehaviorSubject<Pentest[]> = new BehaviorSubject<Pentest[]>([]);
|
||||
// Needed for pentest enabling and disabling
|
||||
selectedProjectId$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||
|
||||
getters: NbGetters<ObjectiveEntry, ObjectiveEntry> = {
|
||||
dataGetter: (node: ObjectiveEntry) => node,
|
||||
childrenGetter: (node: ObjectiveEntry) => node.childEntries || undefined,
|
||||
expandedGetter: (node: ObjectiveEntry) => !!node.expanded
|
||||
};
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private pentestService: PentestService,
|
||||
private dialogService: DialogService,
|
||||
private notificationService: NotificationService,
|
||||
private dataSourceBuilder: NbTreeGridDataSourceBuilder<ObjectiveEntry>,
|
||||
private router: Router
|
||||
) {
|
||||
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.selectOnce(ProjectState.project).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedProject: Project) => {
|
||||
this.selectedProjectId$.next(selectedProject.id);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
this.loadPentestData();
|
||||
}
|
||||
|
||||
loadPentestData(): void {
|
||||
this.store.select(ProjectState.selectedCategory).pipe(
|
||||
switchMap(category => this.pentestService.loadPentests(category)),
|
||||
tap(() => this.loading$.next(true)),
|
||||
catchError(_ => of(null)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (pentests: Pentest[]) => {
|
||||
// Sort data without before adding as table data source
|
||||
const sortedPentests = pentests.sort((a: Pentest, b: Pentest) =>
|
||||
sortDescending(a.refNumber.toLowerCase(), b.refNumber.toLowerCase())
|
||||
);
|
||||
this.pentests$.next(sortedPentests);
|
||||
this.data = transformPentestsToObjectiveEntries(sortedPentests);
|
||||
this.dataSource.setData(this.data, this.getters);
|
||||
this.loading$.next(false);
|
||||
},
|
||||
error: error => {
|
||||
this.loading$.next(false);
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickRouteToObjectivePentest(selectedPentest: Pentest): void {
|
||||
if (selectedPentest.enabled) {
|
||||
|
||||
this.router.navigate([Route.PENTEST_OBJECTIVE])
|
||||
.then(
|
||||
() => this.store.reset({
|
||||
...this.store.snapshot(),
|
||||
})
|
||||
).finally();
|
||||
// Change Pentest State
|
||||
const statePentest: Pentest = this.pentests$.getValue().find(pentest => pentest.refNumber === selectedPentest.refNumber);
|
||||
if (statePentest) {
|
||||
this.store.dispatch(new ChangePentest(statePentest));
|
||||
} else {
|
||||
let childEntryStatePentest;
|
||||
// ToDo: Fix wrong selection
|
||||
// tslint:disable-next-line:prefer-for-of
|
||||
for (let i = 0; i < this.pentests$.getValue().length; i++) {
|
||||
if (this.pentests$.getValue()[i].childEntries) {
|
||||
const findingResult = this.pentests$.getValue()[i].childEntries.find(cE => cE.refNumber === selectedPentest.refNumber);
|
||||
if (findingResult) {
|
||||
childEntryStatePentest = findingResult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.store.dispatch(new ChangePentest(childEntryStatePentest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClickDisableOrEnableObjective(pentest): void {
|
||||
if (pentest.data.enabled) {
|
||||
const message = {
|
||||
title: 'pentest.disable.title',
|
||||
key: 'pentest.disable.key',
|
||||
data: {name: pentest.data.refNumber},
|
||||
};
|
||||
this.dialogService.openConfirmDialog(
|
||||
message
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.pentestService.disableObjective(this.selectedProjectId$.getValue(), pentest.data.id).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadPentestData();
|
||||
this.notificationService.showPopup('pentest.popup.disable.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: (err) => {
|
||||
this.notificationService.showPopup('pentest.popup.disable.failed', PopupType.FAILURE);
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.pentestService.enableObjective(this.selectedProjectId$.getValue(), pentest.data.id).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadPentestData();
|
||||
this.notificationService.showPopup('pentest.popup.enable.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: (err) => {
|
||||
this.notificationService.showPopup('pentest.popup.enable.failed', PopupType.FAILURE);
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// HTML only
|
||||
getTitle(refNumber: string): string {
|
||||
return getTitleKeyForRefNumber(refNumber);
|
||||
}
|
||||
|
||||
// HTML only
|
||||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
}
|
||||
|
||||
enum ObjectiveColumns {
|
||||
TEST_ID = 'testId',
|
||||
TITLE = 'title',
|
||||
STATUS = 'status',
|
||||
FINDINGS_AND_COMMENTS = 'findings&comments',
|
||||
ACTIONS = 'actions'
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
export {PentestOverviewModule} from './pentest-overview.module';
|
||||
export {PentestOverviewRoutingModule} from './pentest-overview-routing.module';
|
|
@ -1,5 +0,0 @@
|
|||
<div class="pentest-categories">
|
||||
<nb-menu class="menu-style" tag="menu" [items]="categories"></nb-menu>
|
||||
</div>
|
||||
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<div class="pentest-header" fxLayout="row" fxLayoutGap="2rem" fxLayoutAlign="space-between center">
|
||||
<div class="back-button-container">
|
||||
<button nbButton
|
||||
shape="round"
|
||||
title="{{ 'global.action.return' | translate }}"
|
||||
(click)="onClickRouteBack()">
|
||||
<fa-icon [icon]="fa.faLongArrowAltLeft"
|
||||
class="back-element-icon fa-lg"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<h4>{{selectedProjectTitle$.getValue()}}</h4>
|
||||
|
||||
<div class="export-button-container">
|
||||
<nb-actions size="medium">
|
||||
<nb-action>
|
||||
<button nbButton hero
|
||||
status="primary"
|
||||
shape="round"
|
||||
(click)="onClickExportPentest()">
|
||||
<fa-icon [icon]="fa.faFileExport"
|
||||
class="export-element-icon fa-lg"></fa-icon>
|
||||
<span class="export-element-text">{{ 'global.action.export' | translate }}</span>
|
||||
</button>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
</div>
|
||||
</div>
|
|
@ -1,22 +0,0 @@
|
|||
.pentest-header {
|
||||
width: calc(100vw - 14%);
|
||||
|
||||
.back-button-container {
|
||||
.back-element-icon {
|
||||
}
|
||||
}
|
||||
|
||||
.export-button-container {
|
||||
display: flex;
|
||||
align-content: flex-end;
|
||||
margin-right: 1rem;
|
||||
|
||||
.export-element-icon {
|
||||
}
|
||||
|
||||
.export-element-text {
|
||||
padding-left: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {Router} from '@angular/router';
|
||||
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-header',
|
||||
templateUrl: './pentest-header.component.html',
|
||||
styleUrls: ['./pentest-header.component.scss']
|
||||
})
|
||||
export class PentestHeaderComponent implements OnInit {
|
||||
|
||||
readonly fa = FA;
|
||||
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||
|
||||
constructor(private store: Store,
|
||||
private readonly router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.select(ProjectState.project).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedProject: Project) => {
|
||||
this.selectedProjectTitle$.next(selectedProject?.title);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickRouteBack(): void {
|
||||
this.router.navigate([Route.PROJECT_OVERVIEW])
|
||||
.then(
|
||||
() => this.store.reset({
|
||||
...this.store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: undefined
|
||||
})
|
||||
).finally();
|
||||
}
|
||||
|
||||
onClickExportPentest(): void {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.info('To be implemented..');
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
|
||||
import {PentestCategoriesComponent} from './pentest-categories/pentest-categories.component';
|
||||
import {PentestTableComponent} from './pentest-table/pentest-table.component';
|
||||
import {
|
||||
NbCardModule,
|
||||
NbLayoutModule,
|
||||
NbTreeGridModule,
|
||||
NbMenuModule,
|
||||
NbListModule,
|
||||
NbButtonModule,
|
||||
NbTooltipModule,
|
||||
NbActionsModule
|
||||
} from '@nebular/theme';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
|
||||
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
PentestHeaderComponent,
|
||||
PentestCategoriesComponent,
|
||||
PentestTableComponent
|
||||
],
|
||||
exports: [
|
||||
PentestHeaderComponent,
|
||||
PentestCategoriesComponent,
|
||||
PentestTableComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
NbMenuModule.forRoot(),
|
||||
NbButtonModule,
|
||||
// nbTooltip crashes app right now if used in component,
|
||||
// workaround: use title in html for now
|
||||
NbTooltipModule,
|
||||
NbTreeGridModule,
|
||||
TranslateModule,
|
||||
StatusTagModule,
|
||||
FindigWidgetModule,
|
||||
RouterModule,
|
||||
NbMenuModule,
|
||||
FormsModule,
|
||||
NbListModule,
|
||||
FontAwesomeModule,
|
||||
FlexLayoutModule,
|
||||
NbActionsModule
|
||||
]
|
||||
})
|
||||
export class PentestOverviewModule {
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<nb-card class="pentest-table">
|
||||
<table [nbTreeGrid]="dataSource">
|
||||
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
|
||||
<tr nbTreeGridRow *nbTreeGridRowDef="let pentest; columns: columns"
|
||||
class="pentest-cell"
|
||||
routerLink="pentest"
|
||||
fragment="{{pentest.data['refNumber']}}"
|
||||
(click)="selectPentest(pentest.data)"
|
||||
[skipLocationChange]="true">
|
||||
</tr>
|
||||
<!-- Test ID -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.testId' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||
<!-- Opens sub categories if row needs to be extendend -->
|
||||
<nb-tree-grid-row-toggle
|
||||
[expanded]="pentest.expanded"
|
||||
*ngIf="pentest.data?.childEntries?.length > 0">
|
||||
</nb-tree-grid-row-toggle>
|
||||
<!---->
|
||||
{{pentest.data['refNumber'] || '-'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Title -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.title' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||
{{ getTitle(pentest.data['refNumber']) | translate }}
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Status -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.status' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||
<app-status-tag [currentStatus]="pentest.data['status']"></app-status-tag>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Findings -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'pentest.findings' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||
<app-findig-widget [numberOfFindigs]="pentest.data['findings']"></app-findig-widget>
|
||||
<!--{{pentest.data['findings'] || '-'}}-->
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
</nb-card>
|
|
@ -1,14 +0,0 @@
|
|||
@import '../../../assets/@theme/styles/themes';
|
||||
|
||||
.pentest-table {
|
||||
width: calc(78vw - 18%);
|
||||
|
||||
.pentest-cell {
|
||||
// Add style here
|
||||
}
|
||||
|
||||
.pentest-cell:hover {
|
||||
cursor: pointer;
|
||||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import {Pentest, PentestEntry, transformPentestsToEntries} from '@shared/models/pentest.model';
|
||||
import {PentestService} from '@shared/services/pentest.service';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {catchError, switchMap} from 'rxjs/operators';
|
||||
import {of} from 'rxjs';
|
||||
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {Router} from '@angular/router';
|
||||
import {ChangePentest} from '@shared/stores/project-state/project-state.actions';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-table',
|
||||
templateUrl: './pentest-table.component.html',
|
||||
styleUrls: ['./pentest-table.component.scss']
|
||||
})
|
||||
export class PentestTableComponent implements OnInit {
|
||||
|
||||
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];
|
||||
dataSource: NbTreeGridDataSource<PentestEntry>;
|
||||
|
||||
private data: PentestEntry[] = [];
|
||||
|
||||
getters: NbGetters<PentestEntry, PentestEntry> = {
|
||||
dataGetter: (node: PentestEntry) => node,
|
||||
childrenGetter: (node: PentestEntry) => node.childEntries || undefined,
|
||||
expandedGetter: (node: PentestEntry) => !!node.expanded,
|
||||
};
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private pentestService: PentestService,
|
||||
private dataSourceBuilder: NbTreeGridDataSourceBuilder<PentestEntry>,
|
||||
private readonly router: Router
|
||||
) {
|
||||
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadPentestData();
|
||||
}
|
||||
|
||||
loadPentestData(): void {
|
||||
this.store.select(ProjectState.selectedCategory).pipe(
|
||||
switchMap(category => this.pentestService.loadPentests(category)),
|
||||
catchError(_ => of(null)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (pentests: Pentest[]) => {
|
||||
this.data = transformPentestsToEntries(pentests);
|
||||
this.dataSource.setData(this.data, this.getters);
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
selectPentest(pentest: Pentest): void {
|
||||
/* ToDo: Include again after fixing pentest route
|
||||
this.router.navigate([Route.PENTEST])
|
||||
.then(
|
||||
() => this.store.reset({
|
||||
...this.store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: undefined
|
||||
})
|
||||
).finally();
|
||||
*/
|
||||
this.store.dispatch(new ChangePentest(pentest.id));
|
||||
|
||||
}
|
||||
|
||||
// HTML only
|
||||
getTitle(refNumber: string): string {
|
||||
return getTitleKeyForRefNumber(refNumber);
|
||||
}
|
||||
}
|
||||
|
||||
enum PentestColumns {
|
||||
TEST_ID = 'testId',
|
||||
TITLE = 'title',
|
||||
STATUS = 'status',
|
||||
FINDINGS = 'findings'
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<nb-layout>
|
||||
<nb-layout-header>
|
||||
<p>pentest works!</p>
|
||||
</nb-layout-header>
|
||||
</nb-layout>
|
|
@ -1,21 +0,0 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {PentestComponent} from './pentest.component';
|
||||
import {NbLayoutModule} from '@nebular/theme';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
PentestComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{
|
||||
path: '',
|
||||
component: PentestComponent
|
||||
}]),
|
||||
NbLayoutModule
|
||||
]
|
||||
})
|
||||
export class PentestModule {
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<div class="comment-table">
|
||||
<table [nbTreeGrid]="dataSource">
|
||||
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
|
||||
<tr nbTreeGridRow *nbTreeGridRowDef="let comment; columns: columns"
|
||||
class="comment-cell"
|
||||
fragment="{{comment.data['commentId']}}">
|
||||
</tr>
|
||||
<!-- Title -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'comment.title' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment">
|
||||
<span *ngIf=" comment.data['title'].length < 200; else cutTitle">
|
||||
{{ comment.data['title'] }}
|
||||
</span>
|
||||
<ng-template #cutTitle>
|
||||
{{ comment.data['title'].slice(0, 200) + '...' }}
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Description -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'comment.description' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment">
|
||||
<span *ngIf=" comment.data['description'].length < 200; else cutDescription">
|
||||
{{ comment.data['description'] }}
|
||||
</span>
|
||||
<ng-template #cutDescription>
|
||||
{{ comment.data['description'].slice(0, 200) + '...' }}
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Actions -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
||||
<button nbButton hero
|
||||
status="info"
|
||||
size="small"
|
||||
shape="round"
|
||||
class="add-comment-button"
|
||||
[disabled]="pentestInfo$.getValue().status !== inProgressStatus"
|
||||
(click)="onClickAddComment()">
|
||||
<fa-icon [icon]="fa.faPlus" class="new-comment-icon"></fa-icon>
|
||||
{{'comment.add' | translate}}
|
||||
</button>
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment" class="cell-actions">
|
||||
<div fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="1rem">
|
||||
<button nbButton
|
||||
status="primary"
|
||||
size="small"
|
||||
(click)="onClickEditComment(comment)">
|
||||
<fa-icon [icon]="fa.faPencilAlt"></fa-icon>
|
||||
</button>
|
||||
<button nbButton
|
||||
status="danger"
|
||||
size="small"
|
||||
(click)="onClickDeleteComment(comment)">
|
||||
<fa-icon [icon]="fa.faTrash"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div *ngIf="data.length === 0 && loading$.getValue() === false" fxLayout="row" fxLayoutAlign="center center">
|
||||
<p class="error-text">
|
||||
{{'comment.no.comments' | translate}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>
|
|
@ -0,0 +1,49 @@
|
|||
@import '../../../../assets/@theme/styles/themes';
|
||||
@import '../../../../assets/@theme/styles/_text-overflow.scss';
|
||||
|
||||
.comment-table {
|
||||
margin-right: 2rem;
|
||||
padding-right: 2rem;
|
||||
|
||||
.comment-cell {
|
||||
// Add style here
|
||||
height: 4.5rem !important;
|
||||
// max-height: 4.5rem !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.comment-cell:hover {
|
||||
// cursor: default;
|
||||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
}
|
||||
|
||||
.cell {
|
||||
height: 4.5rem !important;
|
||||
max-height: 4.5rem !important;
|
||||
}
|
||||
|
||||
.related-finding-cell {
|
||||
height: 4.5rem !important;
|
||||
max-height: 4.5rem !important;
|
||||
// cursor: pointer;
|
||||
font-family: Courier, serif;
|
||||
color: nb-theme(color-danger-default);
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
width: max-content;
|
||||
max-width: 200px;
|
||||
|
||||
.add-comment-button {
|
||||
.new-comment-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
padding-top: 0.5rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {PentestCommentsComponent} from './pentest-comments.component';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {NbButtonModule, NbTreeGridModule} from '@nebular/theme';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {MockComponent} from 'ng-mocks';
|
||||
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {CommentDialogService} from '@shared/modules/comment-dialog/service/comment-dialog.service';
|
||||
import {CommentDialogServiceMock} from '@shared/modules/comment-dialog/service/comment-dialog.service.mock';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: [],
|
||||
commentIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112']
|
||||
},
|
||||
};
|
||||
|
||||
describe('PentestCommentsComponent', () => {
|
||||
let component: PentestCommentsComponent;
|
||||
let fixture: ComponentFixture<PentestCommentsComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
PentestCommentsComponent,
|
||||
MockComponent(LoadingSpinnerComponent)
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
FontAwesomeModule,
|
||||
NbButtonModule,
|
||||
NbTreeGridModule,
|
||||
ThemeModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: CommentDialogService, useClass: CommentDialogServiceMock},
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestCommentsComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,235 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {filter, tap} from 'rxjs/operators';
|
||||
import {
|
||||
Comment,
|
||||
CommentEntry,
|
||||
transformCommentsToObjectiveEntries
|
||||
} from '@shared/models/comment.model';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {CommentDialogService} from '@shared/modules/comment-dialog/service/comment-dialog.service';
|
||||
import {CommentService} from '@shared/services/api/comment.service';
|
||||
import {UpdatePentestComments} from '@shared/stores/project-state/project-state.actions';
|
||||
import {CommentDialogComponent} from '@shared/modules/comment-dialog/comment-dialog.component';
|
||||
import {Finding} from '@shared/models/finding.model';
|
||||
import {FindingService} from '@shared/services/api/finding.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-comments',
|
||||
templateUrl: './pentest-comments.component.html',
|
||||
styleUrls: ['./pentest-comments.component.scss']
|
||||
})
|
||||
export class PentestCommentsComponent implements OnInit {
|
||||
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
// HTML only for button enabling
|
||||
inProgressStatus: PentestStatus = PentestStatus.IN_PROGRESS;
|
||||
|
||||
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||
// comments$: BehaviorSubject<Comment[]> = new BehaviorSubject<Comment[]>(null);
|
||||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
columns: Array<CommentColumns> = [
|
||||
CommentColumns.TITLE, CommentColumns.DESCRIPTION, CommentColumns.ACTIONS
|
||||
];
|
||||
dataSource: NbTreeGridDataSource<CommentEntry>;
|
||||
data: CommentEntry[] = [];
|
||||
|
||||
getters: NbGetters<CommentEntry, CommentEntry> = {
|
||||
dataGetter: (node: CommentEntry) => node,
|
||||
childrenGetter: (node: CommentEntry) => node.childEntries || undefined,
|
||||
expandedGetter: (node: CommentEntry) => !!node.expanded,
|
||||
};
|
||||
|
||||
constructor(private readonly commentService: CommentService,
|
||||
private readonly findingService: FindingService,
|
||||
private dataSourceBuilder: NbTreeGridDataSourceBuilder<CommentEntry>,
|
||||
private notificationService: NotificationService,
|
||||
private dialogService: DialogService,
|
||||
private commentDialogService: CommentDialogService,
|
||||
private store: Store) {
|
||||
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.select(ProjectState.pentest).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedPentest: Pentest) => {
|
||||
this.pentestInfo$.next(selectedPentest);
|
||||
this.loadCommentsData();
|
||||
this.requestFindingsData(selectedPentest.id);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadCommentsData(): void {
|
||||
this.commentService.getCommentsByPentestId(this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '')
|
||||
.pipe(
|
||||
untilDestroyed(this),
|
||||
/*filter(isNotNullOrUndefined),*/
|
||||
tap(() => this.loading$.next(true))
|
||||
)
|
||||
.subscribe({
|
||||
next: (comments: Comment[]) => {
|
||||
if (comments) {
|
||||
this.data = transformCommentsToObjectiveEntries(comments);
|
||||
} else {
|
||||
this.data = [];
|
||||
}
|
||||
this.dataSource.setData(this.data, this.getters);
|
||||
this.loading$.next(false);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
// ToDo: Implement again after proper lazy loading and routing
|
||||
// this.notificationService.showPopup('comment.popup.not.found', PopupType.FAILURE);
|
||||
this.loading$.next(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickAddComment(): void {
|
||||
this.commentDialogService.openCommentDialog(
|
||||
CommentDialogComponent,
|
||||
this.pentestInfo$.getValue().findingIds,
|
||||
null,
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newComment: Comment) => {
|
||||
this.loadCommentsData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickEditComment(commentEntry): void {
|
||||
this.commentService.getCommentById(commentEntry.data.commentId).pipe(
|
||||
filter(isNotNullOrUndefined),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (existingComment: Comment) => {
|
||||
if (existingComment) {
|
||||
this.commentDialogService.openCommentDialog(
|
||||
CommentDialogComponent,
|
||||
this.pentestInfo$.getValue().findingIds,
|
||||
existingComment,
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (updatedComment: Comment) => {
|
||||
this.loadCommentsData();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notificationService.showPopup('comment.popup.not.available', PopupType.INFO);
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
requestFindingsData(pentestId: string): void {
|
||||
this.findingService.getFindingsByPentestId(pentestId).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (findings: Finding[]) => {
|
||||
// findings.forEach(finding => this.objectiveFindings.push({id: finding.id, title: finding.title} as RelatedFindingOption));
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickDeleteComment(commentEntry): void {
|
||||
const message = {
|
||||
title: 'comment.delete.title',
|
||||
key: 'comment.delete.key',
|
||||
data: {name: commentEntry.data.title},
|
||||
};
|
||||
this.dialogService.openConfirmDialog(
|
||||
message
|
||||
).onClose.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.deleteComment(commentEntry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// HTML only
|
||||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
private deleteComment(commentEntry): void {
|
||||
this.commentService.deleteCommentByPentestAndCommentId(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
commentEntry.data.commentId)
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (deletedComment: any) => {
|
||||
this.store.dispatch(new UpdatePentestComments(deletedComment.id));
|
||||
this.loadCommentsData();
|
||||
this.notificationService.showPopup('comment.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
this.onRequestFailed(commentEntry);
|
||||
this.notificationService.showPopup('comment.popup.delete.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.deleteComment(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum CommentColumns {
|
||||
COMMENT_ID = 'commentId',
|
||||
TITLE = 'title',
|
||||
DESCRIPTION = 'description',
|
||||
RELATED_FINDINGS = 'relatedFindings',
|
||||
ACTIONS = 'actions'
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<div class="pentest-content">
|
||||
<div class="content">
|
||||
<nb-tabset>
|
||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'global.action.info' | translate }}">
|
||||
<app-pentest-info></app-pentest-info>
|
||||
</nb-tab>
|
||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.findings' | translate }}"
|
||||
badgeText="{{currentNumberOfFindings$.getValue()}}" badgeStatus="danger">
|
||||
<app-pentest-findings></app-pentest-findings>
|
||||
</nb-tab>
|
||||
<nb-tab class="pentest-tabset" tabTitle="{{ 'pentest.comments' | translate }}"
|
||||
badgeText="{{currentNumberOfComments$.getValue()}}" badgeStatus="control">
|
||||
<app-pentest-comments></app-pentest-comments>
|
||||
</nb-tab>
|
||||
</nb-tabset>
|
||||
</div>
|
||||
|
||||
<div fxLayoutAlign="end end" class="content-footer">
|
||||
<!--ToDo: Use to put element in bottom-right corner -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
.pentest-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.content {
|
||||
height: 95%;
|
||||
overflow: auto !important;
|
||||
// overflow: hidden !important;
|
||||
|
||||
// ToDo: Fixes tab header but also disables scrolling for content
|
||||
/*nb-tab {
|
||||
position: fixed;
|
||||
}*/
|
||||
|
||||
.content-footer {
|
||||
height: 5%;
|
||||
margin: 1rem 6rem 1rem 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {PentestContentComponent} from './pentest-content.component';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: [],
|
||||
commentIds: []
|
||||
},
|
||||
};
|
||||
|
||||
describe('PentestContentComponent', () => {
|
||||
let component: PentestContentComponent;
|
||||
let fixture: ComponentFixture<PentestContentComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
PentestContentComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestContentComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import {PentestService} from '@shared/services/api/pentest.service';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-content',
|
||||
templateUrl: './pentest-content.component.html',
|
||||
styleUrls: ['./pentest-content.component.scss']
|
||||
})
|
||||
export class PentestContentComponent implements OnInit {
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
|
||||
pentest$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||
currentNumberOfFindings$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
|
||||
currentNumberOfComments$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
|
||||
|
||||
constructor(
|
||||
private readonly pentestService: PentestService,
|
||||
private notificationService: NotificationService,
|
||||
private router: Router,
|
||||
private store: Store) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.select(ProjectState.pentest).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedPentest: Pentest) => {
|
||||
if (selectedPentest) {
|
||||
this.pentest$.next(selectedPentest);
|
||||
const findings = selectedPentest.findingIds ? selectedPentest.findingIds.length : 0;
|
||||
this.currentNumberOfFindings$.next(findings);
|
||||
const comments = selectedPentest.commentIds ? selectedPentest.commentIds.length : 0;
|
||||
this.currentNumberOfComments$.next(comments);
|
||||
} else {
|
||||
this.router.navigate([Route.PROJECT_OVERVIEW]);
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<div class="finding-table">
|
||||
<table [nbTreeGrid]="dataSource">
|
||||
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
|
||||
<tr nbTreeGridRow *nbTreeGridRowDef="let finding; columns: columns"
|
||||
class="finding-cell"
|
||||
fragment="{{finding.data['findingId']}}">
|
||||
</tr>
|
||||
<!-- Title -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'finding.title' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
||||
<span *ngIf=" finding.data['title'].length < 200; else cutTitle">
|
||||
{{ finding.data['title'] }}
|
||||
</span>
|
||||
<ng-template #cutTitle>
|
||||
{{ finding.data['title'].slice(0, 200) + '...' }}
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Severity -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-severity">
|
||||
{{ 'finding.severity' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding" class="cell-severity border-style">
|
||||
<div fxLayoutAlign="center center">
|
||||
<app-severity-tag [currentSeverity]="finding.data['severity']"></app-severity-tag>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Description -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'finding.description' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
||||
<span *ngIf=" finding.data['description'].length < 200; else cutDescription">
|
||||
{{ finding.data['description'] }}
|
||||
</span>
|
||||
<ng-template #cutDescription>
|
||||
{{ finding.data['description'].slice(0, 200) + '...' }}
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Impact -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||
{{ 'finding.impact' | translate }}
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
||||
<span *ngIf=" finding.data['impact'].length < 200; else cutImpact">
|
||||
{{ finding.data['impact'] }}
|
||||
</span>
|
||||
<ng-template #cutImpact>
|
||||
{{ finding.data['impact'].slice(0, 200) + '...' }}
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
<!-- Actions -->
|
||||
<ng-container [nbTreeGridColumnDef]="columns[4]">
|
||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
||||
<button nbButton hero
|
||||
status="info"
|
||||
size="small"
|
||||
shape="round"
|
||||
class="add-finding-button"
|
||||
[disabled]="pentestInfo$.getValue().status !== inProgressStatus"
|
||||
(click)="onClickAddFinding()">
|
||||
<fa-icon [icon]="fa.faPlus" class="new-finding-icon"></fa-icon>
|
||||
{{'finding.add' | translate}}
|
||||
</button>
|
||||
</th>
|
||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding" class="cell-actions">
|
||||
<div fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="1rem">
|
||||
<button nbButton
|
||||
status="primary"
|
||||
size="small"
|
||||
(click)="onClickEditFinding(finding)">
|
||||
<fa-icon [icon]="fa.faPencilAlt"></fa-icon>
|
||||
</button>
|
||||
<button nbButton
|
||||
status="danger"
|
||||
size="small"
|
||||
(click)="onClickDeleteFinding(finding)">
|
||||
<fa-icon [icon]="fa.faTrash"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div *ngIf="data.length === 0 && loading$.getValue() === false" fxLayout="row" fxLayoutAlign="center center">
|
||||
<p class="error-text">
|
||||
{{'finding.no.findings' | translate}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>
|
|
@ -0,0 +1,54 @@
|
|||
@import '../../../../assets/@theme/styles/themes';
|
||||
@import '../../../../assets/@theme/styles/_text-overflow.scss';
|
||||
|
||||
.finding-table {
|
||||
margin-right: 2rem;
|
||||
padding-right: 2rem;
|
||||
|
||||
.finding-cell {
|
||||
// Add style here
|
||||
height: 4.5rem !important;
|
||||
// max-height: 4.5rem !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.finding-cell:hover {
|
||||
// cursor: default;
|
||||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
}
|
||||
|
||||
.cell-severity {
|
||||
//width: 125px;
|
||||
// max-width: 125px;
|
||||
// border-style: none;
|
||||
// ToDo: Fix size issue on lower screen resolution
|
||||
// height: 4.5rem !important;
|
||||
}
|
||||
|
||||
.cell {
|
||||
height: 4.5rem !important;
|
||||
max-height: 4.5rem !important;
|
||||
}
|
||||
|
||||
.border-style {
|
||||
border-top-style: none;
|
||||
border-left-style: none;
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
width: max-content;
|
||||
max-width: 180px;
|
||||
|
||||
.add-finding-button {
|
||||
.new-finding-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
padding-top: 0.5rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {PentestFindingsComponent} from './pentest-findings.component';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {NbButtonModule, NbTreeGridModule} from '@nebular/theme';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {MockComponent} from 'ng-mocks';
|
||||
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {FindingDialogService} from '@shared/modules/finding-dialog/service/finding-dialog.service';
|
||||
import {FindingDialogServiceMock} from '@shared/modules/finding-dialog/service/finding-dialog.service.mock';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112'],
|
||||
commentIds: []
|
||||
},
|
||||
};
|
||||
|
||||
describe('PentestFindingsComponent', () => {
|
||||
let component: PentestFindingsComponent;
|
||||
let fixture: ComponentFixture<PentestFindingsComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
PentestFindingsComponent,
|
||||
MockComponent(LoadingSpinnerComponent)
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
FontAwesomeModule,
|
||||
NbButtonModule,
|
||||
NbTreeGridModule,
|
||||
ThemeModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: FindingDialogService, useClass: FindingDialogServiceMock},
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestFindingsComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
component.pentestInfo$.next(DESIRED_PROJECT_STATE_SESSION.selectedPentest);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,217 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import { filter, tap} from 'rxjs/operators';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {
|
||||
Finding,
|
||||
FindingEntry,
|
||||
transformFindingsToObjectiveEntries,
|
||||
} from '@shared/models/finding.model';
|
||||
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
import {FindingDialogService} from '@shared/modules/finding-dialog/service/finding-dialog.service';
|
||||
import {FindingDialogComponent} from '@shared/modules/finding-dialog/finding-dialog.component';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {UpdatePentestFindings} from '@shared/stores/project-state/project-state.actions';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {FindingService} from '@shared/services/api/finding.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-findings',
|
||||
templateUrl: './pentest-findings.component.html',
|
||||
styleUrls: ['./pentest-findings.component.scss']
|
||||
})
|
||||
export class PentestFindingsComponent implements OnInit {
|
||||
|
||||
constructor(private findingService: FindingService,
|
||||
private dataSourceBuilder: NbTreeGridDataSourceBuilder<FindingEntry>,
|
||||
private readonly notificationService: NotificationService,
|
||||
private dialogService: DialogService,
|
||||
private findingDialogService: FindingDialogService,
|
||||
private store: Store) {
|
||||
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
|
||||
}
|
||||
|
||||
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
// HTML only for button enabling
|
||||
inProgressStatus: PentestStatus = PentestStatus.IN_PROGRESS;
|
||||
|
||||
columns: Array<FindingColumns> = [
|
||||
FindingColumns.TITLE, FindingColumns.SEVERITY, FindingColumns.DESCRIPTION, FindingColumns.IMPACT, FindingColumns.ACTIONS
|
||||
];
|
||||
dataSource: NbTreeGridDataSource<FindingEntry>;
|
||||
|
||||
data: FindingEntry[] = [];
|
||||
|
||||
getters: NbGetters<FindingEntry, FindingEntry> = {
|
||||
dataGetter: (node: FindingEntry) => node,
|
||||
childrenGetter: (node: FindingEntry) => node.childEntries || undefined,
|
||||
expandedGetter: (node: FindingEntry) => !!node.expanded,
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.select(ProjectState.pentest).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedPentest: Pentest) => {
|
||||
this.pentestInfo$.next(selectedPentest);
|
||||
this.loadFindingsData();
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadFindingsData(): void {
|
||||
this.findingService.getFindingsByPentestId(this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '')
|
||||
.pipe(
|
||||
untilDestroyed(this),
|
||||
/*filter(isNotNullOrUndefined),*/
|
||||
tap(() => this.loading$.next(true))
|
||||
)
|
||||
.subscribe({
|
||||
next: (findings: Finding[]) => {
|
||||
// ToDo: Handle this case before in pipe
|
||||
if (findings) {
|
||||
this.data = transformFindingsToObjectiveEntries(findings);
|
||||
} else {
|
||||
this.data = [];
|
||||
}
|
||||
this.dataSource.setData(this.data, this.getters);
|
||||
this.loading$.next(false);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
// ToDo: Implement again after proper lazy loading and routing
|
||||
// this.notificationService.showPopup('findings.popup.not.found', PopupType.FAILURE);
|
||||
this.loading$.next(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickAddFinding(): void {
|
||||
this.findingDialogService.openFindingDialog(
|
||||
FindingDialogComponent,
|
||||
null,
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (newFinding: Finding) => {
|
||||
this.loadFindingsData();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickEditFinding(findingEntry): void {
|
||||
this.findingService.getFindingById(findingEntry.data.findingId).pipe(
|
||||
filter(isNotNullOrUndefined),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (existingFinding: Finding) => {
|
||||
if (existingFinding) {
|
||||
this.findingDialogService.openFindingDialog(
|
||||
FindingDialogComponent,
|
||||
existingFinding,
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
},
|
||||
this.pentestInfo$.getValue()
|
||||
).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (updatedFinding: Finding) => {
|
||||
this.loadFindingsData();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notificationService.showPopup('finding.popup.not.available', PopupType.INFO);
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickDeleteFinding(findingEntry): void {
|
||||
const message = {
|
||||
title: 'finding.delete.title',
|
||||
key: 'finding.delete.key',
|
||||
data: {name: findingEntry.data.title},
|
||||
};
|
||||
this.dialogService.openConfirmDialog(
|
||||
message
|
||||
).onClose.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.deleteFinding(findingEntry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
private deleteFinding(findingEntry): void {
|
||||
this.findingService.deleteFindingByPentestAndFindingId(
|
||||
this.pentestInfo$.getValue() ? this.pentestInfo$.getValue().id : '',
|
||||
findingEntry.data.findingId)
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (deletedFinding: any) => {
|
||||
this.store.dispatch(new UpdatePentestFindings(deletedFinding.id));
|
||||
this.loadFindingsData();
|
||||
this.notificationService.showPopup('finding.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
this.onRequestFailed(findingEntry);
|
||||
this.notificationService.showPopup('finding.popup.delete.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onRequestFailed(retryParameter: any): void {
|
||||
this.dialogService.openRetryDialog({key: 'global.retry.dialog', data: null}).onClose
|
||||
.pipe(
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe((ref) => {
|
||||
if (ref.retry) {
|
||||
this.deleteFinding(retryParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum FindingColumns {
|
||||
FINDING_ID = 'findingId',
|
||||
TITLE = 'title',
|
||||
SEVERITY = 'severity',
|
||||
DESCRIPTION = 'description',
|
||||
IMPACT = 'impact',
|
||||
ACTIONS = 'actions'
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<div class="pentest-info">
|
||||
<h4>
|
||||
{{ getPentestHeaderForObjective(pentestInfo$.getValue().refNumber) | translate}}
|
||||
</h4>
|
||||
<div class="description">
|
||||
<div>
|
||||
{{ getPentestInfoForObjective(pentestInfo$.getValue().refNumber) | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<!--ToDo: Add tooling hints after description (maybe in pentest-header component)-->
|
||||
</div>
|
|
@ -0,0 +1,16 @@
|
|||
.pentest-info {
|
||||
overflow: hidden !important;
|
||||
position: relative !important;
|
||||
|
||||
.description {
|
||||
// ToDo: Make only description scrollable
|
||||
// Scrollbar
|
||||
overflow-y: scroll !important;
|
||||
overflow-x: hidden;
|
||||
scroll-behavior: smooth;
|
||||
|
||||
width: 60vw;
|
||||
font-size: 1rem;
|
||||
white-space: pre-line;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {PentestInfoComponent} from './pentest-info.component';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112'],
|
||||
commentIds: []
|
||||
},
|
||||
};
|
||||
|
||||
describe('PentestInfoComponent', () => {
|
||||
let component: PentestInfoComponent;
|
||||
let fixture: ComponentFixture<PentestInfoComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
PentestInfoComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
FontAwesomeModule,
|
||||
ThemeModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestInfoComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
component.pentestInfo$.next({
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: [],
|
||||
commentIds: []
|
||||
});
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Pentest} from '@shared/models/pentest.model';
|
||||
import {getPentestInfoForObjective} from '@shared/functions/infos/get-pentest-info-for-objective';
|
||||
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {Store} from '@ngxs/store';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-info',
|
||||
templateUrl: './pentest-info.component.html',
|
||||
styleUrls: ['./pentest-info.component.scss']
|
||||
})
|
||||
export class PentestInfoComponent implements OnInit {
|
||||
|
||||
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||
|
||||
constructor(private store: Store) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.selectOnce(ProjectState.pentest).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedPentest: Pentest) => {
|
||||
this.pentestInfo$.next(selectedPentest);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getPentestHeaderForObjective(refNumber: string): string {
|
||||
return getTitleKeyForRefNumber(refNumber);
|
||||
}
|
||||
|
||||
getPentestInfoForObjective(refNumber: string): string {
|
||||
return getPentestInfoForObjective(refNumber);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<div class="pentest-header" fxLayout="row" fxLayoutGap="2rem" fxLayoutAlign="space-between center">
|
||||
<div class="exit-button-container">
|
||||
<button nbButton
|
||||
shape="round"
|
||||
title="{{ 'global.action.exit' | translate }}"
|
||||
(click)="onClickRouteBack()">
|
||||
<fa-icon [icon]="fa.faLongArrowAltLeft"
|
||||
class="exit-element-icon fa-lg">
|
||||
</fa-icon>
|
||||
<span class="exit-element-text"> {{ 'global.action.exit' | translate }} </span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="header-info" fxLayout="row" fxHide.lt-lg>
|
||||
<span class="project-title">{{selectedProjectTitle$.getValue()}}</span>
|
||||
<span class="pentest-ref">{{" / " + pentest$.getValue().refNumber}}</span>
|
||||
</div>
|
||||
<div class="header-info-mobile" fxHide fxShow.lt-lg>
|
||||
<span class="pentest-ref">{{pentest$.getValue().refNumber}}</span>
|
||||
</div>
|
||||
|
||||
<div class="pentest-status-container" fxLayout="row" fxLayoutGap="2.5rem" fxLayoutAlign="end center">
|
||||
<!-- Pentest Timer-->
|
||||
<div class="timer-component">
|
||||
<app-timer></app-timer>
|
||||
</div>
|
||||
<!-- Complete Pentest -->
|
||||
<div>
|
||||
<button nbButton
|
||||
class="complete-pentest-button"
|
||||
status="success"
|
||||
[disabled]="!pentestStatusChanged() || !pentestHasFindingsOrComments()"
|
||||
title="{{ 'global.action.save' | translate }}"
|
||||
(click)="onClickCompletePentest()">
|
||||
<fa-icon [icon]="fa.faSquare"></fa-icon>
|
||||
<span class="action-element-text"> {{ 'global.action.complete' | translate }} </span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
@import '../../../assets/@theme/styles/_text-overflow.scss';
|
||||
|
||||
.pentest-header {
|
||||
width: 100vw;
|
||||
|
||||
.header-info {
|
||||
position: absolute;
|
||||
margin-left: 10rem;
|
||||
margin-right: 10rem;
|
||||
text-align: center;
|
||||
|
||||
.project-title {
|
||||
@include multiLineEllipsis($font-size: 1.5rem, $font-weight: bold, $line-height: 2rem, $lines-to-show: 1, $max-width: 32rem);
|
||||
}
|
||||
|
||||
.pentest-ref {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
line-height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-info-mobile{
|
||||
position: absolute;
|
||||
margin-left: 10rem;
|
||||
margin-right: 10rem;
|
||||
text-align: center;
|
||||
|
||||
.pentest-ref {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
line-height: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.exit-button-container {
|
||||
.exit-element-icon {
|
||||
}
|
||||
|
||||
.exit-element-text {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pentest-status-container {
|
||||
position: fixed;
|
||||
right: 4rem;
|
||||
// display: flex;
|
||||
// align-content: flex-end;
|
||||
|
||||
.timer-component {
|
||||
height: 2rem !important;
|
||||
max-height: 2rem !important;
|
||||
margin: 0.5rem 2.25rem 1rem 0;
|
||||
}
|
||||
|
||||
.complete-pentest-button {
|
||||
// position: absolute;
|
||||
|
||||
.action-element-text {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pentest-status-dialog {
|
||||
margin: 1rem 2.25rem 1rem 0;
|
||||
|
||||
.status {
|
||||
width: 12rem;
|
||||
}
|
||||
|
||||
.basic {
|
||||
background-color: nb-theme(color-basic-default);
|
||||
}
|
||||
|
||||
.info {
|
||||
background-color: nb-theme(color-info-default);
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: nb-theme(color-warning-default);
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: nb-theme(color-success-default);
|
||||
}
|
||||
}
|
||||
|
||||
.save-pentest-button {
|
||||
// height: 1rem !important;
|
||||
margin: 1rem 0 1rem 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {PentestHeaderComponent} from './pentest-header.component';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: [],
|
||||
commentIds: []
|
||||
},
|
||||
};
|
||||
|
||||
describe('PentestHeaderComponent', () => {
|
||||
let component: PentestHeaderComponent;
|
||||
let fixture: ComponentFixture<PentestHeaderComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [PentestHeaderComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([ProjectState])
|
||||
],
|
||||
providers: [
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()},
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PentestHeaderComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,177 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {Router} from '@angular/router';
|
||||
import {ChangePentest} from '@shared/stores/project-state/project-state.actions';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
import {Pentest, transformPentestToRequestBody} from '@shared/models/pentest.model';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {PentestService} from '@shared/services/api/pentest.service';
|
||||
import {StatusText} from '@shared/widgets/status-tag/status-tag.component';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'app-pentest-header',
|
||||
templateUrl: './pentest-header.component.html',
|
||||
styleUrls: ['./pentest-header.component.scss']
|
||||
})
|
||||
export class PentestHeaderComponent implements OnInit, OnDestroy {
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
|
||||
pentest$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||
pentestChanged$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
|
||||
// Pentest Timer Handler
|
||||
currentTimeSpent = 0;
|
||||
private initialTimeSpent: number;
|
||||
|
||||
// Pentest Status Handler
|
||||
status = PentestStatus;
|
||||
currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
|
||||
private initialPentestStatus: PentestStatus;
|
||||
|
||||
// Status Text Translation Texts
|
||||
readonly statusTexts: Array<StatusText> = [
|
||||
{value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
||||
/* ToDo: Disabled not needed inside pentest */
|
||||
/*{value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},*/
|
||||
{value: PentestStatus.PAUSED, translationText: 'pentest.statusText.paused'},
|
||||
{value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
|
||||
{value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
|
||||
];
|
||||
|
||||
selectedProjectId$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||
|
||||
constructor(private store: Store,
|
||||
private pentestService: PentestService,
|
||||
private notificationService: NotificationService,
|
||||
private readonly router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store.selectOnce(ProjectState.project).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedProject: Project) => {
|
||||
this.selectedProjectId$.next(selectedProject.id);
|
||||
this.selectedProjectTitle$.next(selectedProject?.title);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
this.store.select(ProjectState.pentest).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedPentest: Pentest) => {
|
||||
this.currentStatus = selectedPentest.status;
|
||||
this.currentTimeSpent = selectedPentest.timeSpent ? selectedPentest.timeSpent : 0;
|
||||
this.pentest$.next(selectedPentest);
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
// Setup initial values for status and time outside of store subscription
|
||||
this.initialPentestStatus = this.currentStatus;
|
||||
this.initialTimeSpent = this.currentTimeSpent;
|
||||
}
|
||||
|
||||
onClickRouteBack(): void {
|
||||
// Route back to overview
|
||||
this.router.navigate([Route.OBJECTIVE_OVERVIEW])
|
||||
.then(
|
||||
() => {
|
||||
this.store.dispatch(new ChangePentest(null));
|
||||
}
|
||||
).finally();
|
||||
}
|
||||
|
||||
onClickCompletePentest(): void {
|
||||
// Update existing Pentest
|
||||
this.pentest$.next({...this.pentest$.getValue(), status: PentestStatus.COMPLETED, timeSpent: this.currentTimeSpent});
|
||||
this.updatePentest();
|
||||
}
|
||||
|
||||
private updatePentest(): void {
|
||||
this.pentestService.updatePentest(transformPentestToRequestBody(this.pentest$.getValue()))
|
||||
.subscribe({
|
||||
next: (pentest: Pentest) => {
|
||||
this.store.dispatch(new ChangePentest(pentest));
|
||||
this.initialTimeSpent = pentest.timeSpent;
|
||||
this.notificationService.showPopup('pentest.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: err => {
|
||||
console.log(err);
|
||||
this.notificationService.showPopup('pentest.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if initial pentest Status is different from current pentest status
|
||||
*/
|
||||
pentestStatusChanged(): boolean {
|
||||
if (this.initialTimeSpent !== this.currentTimeSpent && this.currentTimeSpent !== 0) {
|
||||
this.pentestChanged$.next(true);
|
||||
} else {
|
||||
this.pentestChanged$.next(false);
|
||||
}
|
||||
return this.pentestChanged$.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if pentest includes at least one finding or comment
|
||||
*/
|
||||
pentestHasFindingsOrComments(): boolean {
|
||||
const pentest: Pentest = this.pentest$.getValue();
|
||||
// Check if pentest includes any findings or comments
|
||||
return pentest?.findingIds?.length > 0 || pentest?.commentIds?.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the correct nb-status for current pentest-status
|
||||
*/
|
||||
getPentestFillStatus(value: PentestStatus): string {
|
||||
let pentestFillStatus;
|
||||
switch (value) {
|
||||
case PentestStatus.NOT_STARTED: {
|
||||
pentestFillStatus = 'basic';
|
||||
break;
|
||||
}
|
||||
case PentestStatus.PAUSED: {
|
||||
pentestFillStatus = 'info';
|
||||
break;
|
||||
}
|
||||
case PentestStatus.IN_PROGRESS: {
|
||||
pentestFillStatus = 'warning';
|
||||
break;
|
||||
}
|
||||
case PentestStatus.COMPLETED: {
|
||||
pentestFillStatus = 'success';
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pentestFillStatus = 'basic';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pentestFillStatus;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.pentestStatusChanged()) {
|
||||
// Save current Pentest before exiting
|
||||
this.pentest$.next({...this.pentest$.getValue(), status: PentestStatus.PAUSED, timeSpent: this.currentTimeSpent});
|
||||
this.updatePentest();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,5 +8,5 @@ const routes: Routes = [
|
|||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PentestOverviewRoutingModule {
|
||||
export class PentestRoutingModule {
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<div fxFlex class="pentest">
|
||||
<nb-layout fxFlex>
|
||||
<nb-layout-header fxFlex="0 1 max-content" class="stepper-column">
|
||||
<app-pentest-header></app-pentest-header>
|
||||
</nb-layout-header>
|
||||
|
||||
<nb-layout-column fxFlex="0 1 max-content" class="column-wrapper">
|
||||
<nb-card class="content-column">
|
||||
<nb-card-body>
|
||||
<app-pentest-content></app-pentest-content>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
</nb-layout-column>
|
||||
</nb-layout>
|
||||
</div>
|
|
@ -0,0 +1,24 @@
|
|||
@import '../../assets/@theme/styles/themes';
|
||||
@import '../../assets/@theme/styles/variables';
|
||||
|
||||
.pentest {
|
||||
width: 100vw;
|
||||
height: calc(100vh - #{$header-height});
|
||||
overflow: hidden;
|
||||
|
||||
.header-column {
|
||||
width: 100vw;
|
||||
height: $pentest-header-height;
|
||||
}
|
||||
|
||||
.column-wrapper {
|
||||
padding-left: 0 !important;
|
||||
|
||||
.content-column {
|
||||
overflow: auto !important;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
height: calc(100vh - #{$pentest-header-height} - #{$header-height});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,6 @@ export class PentestComponent implements OnInit {
|
|||
|
||||
ngOnInit(): void {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.info('pentest component renderd');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {PentestComponent} from './pentest.component';
|
||||
import {NbButtonModule, NbCardModule, NbLayoutModule, NbSelectModule, NbTabsetModule, NbTreeGridModule} from '@nebular/theme';
|
||||
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
|
||||
import {PentestContentComponent} from './pentest-content/pentest-content.component';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
|
||||
import {PentestInfoComponent} from './pentest-content/pentest-info/pentest-info.component';
|
||||
import {PentestFindingsComponent} from './pentest-content/pentest-findings/pentest-findings.component';
|
||||
import {PentestCommentsComponent} from './pentest-content/pentest-comments/pentest-comments.component';
|
||||
import {CommonAppModule} from '../common-app.module';
|
||||
import {SeverityTagModule} from '@shared/widgets/severity-tag/severity-tag.module';
|
||||
import {FindingDialogModule} from '@shared/modules/finding-dialog/finding-dialog.module';
|
||||
import {CommentDialogModule} from '@shared/modules/comment-dialog/comment-dialog.module';
|
||||
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
||||
import {TimerModule} from '@shared/modules/timer/timer.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
PentestComponent,
|
||||
PentestHeaderComponent,
|
||||
PentestContentComponent,
|
||||
PentestInfoComponent,
|
||||
PentestFindingsComponent,
|
||||
PentestCommentsComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CommonAppModule,
|
||||
RouterModule.forChild([{
|
||||
path: '',
|
||||
component: PentestComponent
|
||||
}]),
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
FlexLayoutModule,
|
||||
FontAwesomeModule,
|
||||
TranslateModule,
|
||||
NbButtonModule,
|
||||
StatusTagModule,
|
||||
NbTabsetModule,
|
||||
NbTreeGridModule,
|
||||
SeverityTagModule,
|
||||
NbSelectModule,
|
||||
// Dialog Modules
|
||||
FindingDialogModule,
|
||||
CommentDialogModule,
|
||||
FindigWidgetModule,
|
||||
// Modules
|
||||
TimerModule,
|
||||
]
|
||||
})
|
||||
export class PentestModule {
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {ProjectOverviewComponent} from './project-overview.component';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ProjectOverviewComponent
|
||||
},
|
||||
{
|
||||
path: 'id',
|
||||
path: Route.OBJECTIVE_OVERVIEW,
|
||||
loadChildren: () => import('./project').then(mod => mod.ProjectModule),
|
||||
}
|
||||
];
|
||||
|
|
|
@ -1,84 +1,68 @@
|
|||
<div fxLayout="row" fxLayoutGap="2rem">
|
||||
<div *ngFor="let project of projects | async">
|
||||
<nb-card class="project-card" accent="success">
|
||||
<nb-card-header fxLayoutAlign="start center"
|
||||
routerLink="id"
|
||||
fragment="{{project.id}}"
|
||||
class="project-link project-header"
|
||||
[state]="{selectedProject:project}">
|
||||
<h4>{{project?.title}}</h4>
|
||||
</nb-card-header>
|
||||
<nb-card-body class="project-link"
|
||||
routerLink="id"
|
||||
fragment="{{project.id}}"
|
||||
[state]="{selectedProject:project}">
|
||||
<p class="project-subheader">
|
||||
{{'project.client' | translate}}:
|
||||
</p>
|
||||
<span class="project-paragraph">
|
||||
{{project?.client}}
|
||||
</span>
|
||||
|
||||
<p class="project-subheader">
|
||||
{{'project.tester' | translate}}:
|
||||
</p>
|
||||
<span class="project-paragraph">
|
||||
{{project?.tester}}
|
||||
</span>
|
||||
|
||||
<p class="project-subheader">
|
||||
{{'project.createdAt' | translate}}:
|
||||
</p>
|
||||
<span class="project-paragraph">
|
||||
{{project?.createdAt | dateTimeFormat}}
|
||||
</span>
|
||||
</nb-card-body>
|
||||
<nb-card-footer>
|
||||
<!--ToDo: Display correct progress of project-->
|
||||
<div fxLayout="row" fxLayoutGap="1rem" fxLayoutAlign="start end">
|
||||
<nb-progress-bar class="project-progress"
|
||||
status="warning"
|
||||
[value]="40"
|
||||
[displayValue]="true">
|
||||
</nb-progress-bar>
|
||||
<button nbButton
|
||||
status="primary"
|
||||
size="small"
|
||||
class="project-button"
|
||||
(click)="onClickEditProject(project)">
|
||||
<fa-icon [icon]="fa.faPencilAlt"></fa-icon>
|
||||
</button>
|
||||
<div fxFlex="0 1 max-content" fxLayout="column" class="pentest-overview">
|
||||
<nb-layout fxFlex>
|
||||
<!--Header-->
|
||||
<nb-layout-header class="pentest-overview-header">
|
||||
<div fxLayout="row" fxLayoutGap="2rem" fxLayoutAlign="space-between center">
|
||||
<!--Filter-->
|
||||
<div fxLayout="row" fxLayoutGap="1rem" class="header-filer">
|
||||
<!--Actions-->
|
||||
<form class="project-filter-input">
|
||||
<nb-form-field>
|
||||
<fa-icon nbPrefix class="search-prefix-icon" [icon]="fa.faSearch"></fa-icon>
|
||||
<input type="search"
|
||||
fullWidth nbInput
|
||||
class="search-field"
|
||||
[formControl]="projectSearch"
|
||||
placeholder="{{ 'project.filter.placeholder' | translate: this.allProjectsCount$?.getValue() }}"
|
||||
status="basic"
|
||||
shape="semi-round"
|
||||
fieldSize="medium">
|
||||
</nb-form-field>
|
||||
</form>
|
||||
<!--ToDo: Add dropdown to filter for specific state-->
|
||||
<button nbButton
|
||||
status="danger"
|
||||
size="small"
|
||||
class="project-button"
|
||||
(click)="onClickDeleteProject(project)">
|
||||
<fa-icon [icon]="fa.faTrash"></fa-icon>
|
||||
outline
|
||||
size="medium"
|
||||
shape="semi-round"
|
||||
class="reset-filter-btn"
|
||||
[disabled]="projectSearch.value === ''"
|
||||
(click)="onClickResetFilter()">
|
||||
<fa-icon [icon]="fa.faFilterCircleXmark" class="btn-icon"></fa-icon>
|
||||
{{'global.action.reset' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</nb-card-footer>
|
||||
</nb-card>
|
||||
</div>
|
||||
<!--Button-->
|
||||
<div class="header-project-button">
|
||||
<button nbButton hero
|
||||
status="info"
|
||||
size="medium"
|
||||
shape="round"
|
||||
class="add-project-button"
|
||||
(click)="onClickAddProject()">
|
||||
<fa-icon [icon]="fa.faPlus" class="btn-icon"></fa-icon>
|
||||
{{'project.overview.add.project' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nb-layout-header>
|
||||
<!--Column-->
|
||||
<!--ToDo: Fix the column style for multiple projects in css-->
|
||||
<nb-layout-column class="pentest-overview-column">
|
||||
<div class="project-grid">
|
||||
<div class="project" *ngFor="let project of projects$ | async">
|
||||
<app-project-widget [project]="project"></app-project-widget>
|
||||
</div>
|
||||
</div>
|
||||
<!--Error Text-->
|
||||
<div *ngIf="projects$.getValue() == null || projects$.getValue().length === 0 && loading$.getValue() === false"
|
||||
fxLayout="row" fxLayoutAlign="center center">
|
||||
<p class="error-text">
|
||||
{{'project.overview.no.projects' | translate}}
|
||||
</p>
|
||||
</div>
|
||||
<!--Loading Spinner-->
|
||||
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>
|
||||
</nb-layout-column>
|
||||
</nb-layout>
|
||||
</div>
|
||||
|
||||
<div *ngIf="projects.getValue().length === 0 || !isLoading()" fxLayout="row" fxLayoutAlign="center center">
|
||||
<p class="error-text">
|
||||
{{'project.overview.no.projects' | translate}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div fxLayoutAlign="end end">
|
||||
<button nbButton
|
||||
status="primary"
|
||||
size="large"
|
||||
shape="round"
|
||||
class="add-project-button"
|
||||
(click)="onClickAddProject()">
|
||||
<fa-icon [icon]="fa.faPlus" class="new-project-icon"></fa-icon>
|
||||
{{'project.overview.add.project' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<app-loading-spinner [isLoading$]="isLoading()" *ngIf="isLoading() | async"></app-loading-spinner>
|
||||
|
||||
|
||||
|
|
|
@ -1,62 +1,88 @@
|
|||
@import '../../assets/@theme/styles/themes';
|
||||
@import '../../assets/@theme/styles/variables';
|
||||
@import '../../assets/@theme/styles/_text-overflow.scss';
|
||||
|
||||
.project-card {
|
||||
max-width: 22rem;
|
||||
width: 22rem;
|
||||
min-width: 20rem;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
.pentest-overview {
|
||||
width: 100vw;
|
||||
height: 85vh;
|
||||
overflow: hidden !important;
|
||||
|
||||
.project-header {
|
||||
max-height: 8rem;
|
||||
height: 8rem;
|
||||
min-height: 6rem;
|
||||
.pentest-overview-header {
|
||||
width: 100vw;
|
||||
height: 5rem;
|
||||
|
||||
.header-filer {
|
||||
.project-filter-input {
|
||||
width: 24rem;
|
||||
border-color: nb-theme(color-control-default);
|
||||
|
||||
|
||||
.search-field:active {
|
||||
color: nb-theme(color-info-default);
|
||||
// opacity: initial;
|
||||
}
|
||||
|
||||
.search-prefix-icon:active {
|
||||
color: nb-theme(color-info-default);
|
||||
}
|
||||
}
|
||||
|
||||
.state-dialog {
|
||||
margin-left: auto;
|
||||
margin-right: 0;
|
||||
|
||||
.states {
|
||||
width: 14rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.reset-filter-btn {
|
||||
.btn-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-project-button {
|
||||
position: fixed;
|
||||
right: 1.5rem;
|
||||
|
||||
.add-project-button {
|
||||
// align-content: flex-end;
|
||||
margin: 6rem 2rem 6rem 0;
|
||||
|
||||
.btn-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.project-subheader {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.pentest-overview-column {
|
||||
width: 100vw;
|
||||
// ToDo: Adjust this property when adding footer
|
||||
height: calc(100% - 15rem) !important;
|
||||
max-height: 100vh !important;
|
||||
margin-top: 1.25rem;
|
||||
// Scrollbar
|
||||
overflow-y: scroll !important;
|
||||
overflow-x: hidden;
|
||||
scroll-behavior: smooth;
|
||||
|
||||
.project-paragraph {
|
||||
font-size: 1.15rem;
|
||||
font-style: italic;
|
||||
}
|
||||
.project-grid {
|
||||
display: grid;
|
||||
/* define the number of grid columns */
|
||||
grid-template-columns: repeat( auto-fill, minmax(24rem, 1fr) );
|
||||
|
||||
.project-progress {
|
||||
max-width: 65%;
|
||||
width: 65%;
|
||||
min-width: 65%;
|
||||
}
|
||||
.project {
|
||||
padding-bottom: 1.25rem;
|
||||
height: max-content;
|
||||
}
|
||||
}
|
||||
|
||||
.project-button {
|
||||
height: 1.425rem;
|
||||
.error-text {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
background-color: nb-theme(color-basic-transparent-focus);
|
||||
// Increases element size on hover
|
||||
// Decreases usability which is why it is commented out
|
||||
/*
|
||||
margin-top: +0.625rem;
|
||||
transform: scale(1.025);
|
||||
*/
|
||||
}
|
||||
|
||||
.project-link:hover {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.add-project-button {
|
||||
margin: 6rem 2rem 6rem 0;
|
||||
.new-project-icon {
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -8,17 +8,17 @@ import {NbButtonModule, NbCardModule, NbProgressBarModule, NbSpinnerModule} from
|
|||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {ProjectService} from '@shared/services/project.service';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {HttpLoaderFactory} from '../common-app.module';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {NgxsModule} from '@ngxs/store';
|
||||
import {SessionState} from '@shared/stores/session-state/session-state';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {NotificationService} from '@shared/services/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/notification.service.mock';
|
||||
import {ProjectServiceMock} from '@shared/services/project.service.mock';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {ProjectServiceMock} from '@shared/services/api/project.service.mock';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
|
@ -26,7 +26,7 @@ import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
|||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
||||
import {MockComponent, MockPipe} from 'ng-mocks';
|
||||
import {MockComponent} from 'ng-mocks';
|
||||
|
||||
describe('ProjectOverviewComponent', () => {
|
||||
let component: ProjectOverviewComponent;
|
||||
|
@ -36,19 +36,17 @@ describe('ProjectOverviewComponent', () => {
|
|||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
ProjectOverviewComponent,
|
||||
MockComponent(LoadingSpinnerComponent),
|
||||
MockPipe(DateTimeFormatPipe)
|
||||
MockComponent(LoadingSpinnerComponent)
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ProjectOverviewRoutingModule,
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
FlexLayoutModule,
|
||||
BrowserAnimationsModule,
|
||||
FontAwesomeModule,
|
||||
TranslateModule,
|
||||
NbProgressBarModule,
|
||||
ProjectOverviewRoutingModule,
|
||||
NbSpinnerModule,
|
||||
HttpClientTestingModule,
|
||||
ThemeModule.forRoot(),
|
||||
|
@ -67,7 +65,7 @@ describe('ProjectOverviewComponent', () => {
|
|||
{provide: ProjectService, useValue: new ProjectServiceMock()},
|
||||
{provide: ProjectDialogService, useClass: ProjectDialogServiceMock},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||
{provide: NotificationService, useClass: NotificationServiceMock}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||
import {Project, ProjectDialogBody} from '@shared/models/project.model';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {ProjectService} from '@shared/services/project.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/notification.service';
|
||||
import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||
import {startWith, tap} from 'rxjs/operators';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {Router} from '@angular/router';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {UntypedFormControl} from '@angular/forms';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {SetAvailableProjects} from '@shared/stores/project-state/project-state.actions';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
|
@ -17,32 +22,67 @@ import {ProjectDialogService} from '@shared/modules/project-dialog/service/proje
|
|||
styleUrls: ['./project-overview.component.scss']
|
||||
})
|
||||
export class ProjectOverviewComponent implements OnInit {
|
||||
|
||||
// HTML only
|
||||
readonly fa = FA;
|
||||
|
||||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
projects: BehaviorSubject<Project[]> = new BehaviorSubject<Project[]>([]);
|
||||
projects$: BehaviorSubject<Project[]> = new BehaviorSubject<Project[]>([]);
|
||||
allProjects$: BehaviorSubject<Project[]> = new BehaviorSubject<Project[]>([]);
|
||||
|
||||
// Search
|
||||
projectSearch: UntypedFormControl = new UntypedFormControl();
|
||||
protected filter$: Observable<string>;
|
||||
allProjectsCount$: BehaviorSubject<any> = new BehaviorSubject<any>({allProjectsCount: 0});
|
||||
|
||||
constructor(
|
||||
private readonly projectService: ProjectService,
|
||||
private readonly dialogService: DialogService,
|
||||
private readonly projectDialogService: ProjectDialogService,
|
||||
private readonly notificationService: NotificationService) {
|
||||
private readonly notificationService: NotificationService,
|
||||
private store: Store,
|
||||
private router: Router,
|
||||
private projectService: ProjectService,
|
||||
private dialogService: DialogService,
|
||||
private projectDialogService: ProjectDialogService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Load all available projects
|
||||
this.loadProjects();
|
||||
// Subscribe to project store
|
||||
this.store.select(ProjectState.allProjects).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (projects: Project[]) => {
|
||||
// tslint:disable-next-line:no-console
|
||||
if (projects && projects.length === 0) {
|
||||
this.loadProjects();
|
||||
}
|
||||
// Setup Search Form
|
||||
this.projectSearch = new UntypedFormControl({value: '', disabled: projects?.length === 0});
|
||||
this.setFilterObserverForProjects();
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
loadProjects(): void {
|
||||
this.projectService.getProjects()
|
||||
.pipe(
|
||||
untilDestroyed(this),
|
||||
tap(() => this.loading$.next(true))
|
||||
tap(() => this.loading$.next(true)),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe({
|
||||
next: (projects: Project[]) => {
|
||||
this.projects.next(projects);
|
||||
if (projects) {
|
||||
this.projects$.next(projects);
|
||||
this.allProjects$.next(projects);
|
||||
this.allProjectsCount$.next({allProjectsCount: projects.length});
|
||||
this.store.dispatch(new SetAvailableProjects(projects));
|
||||
} else {
|
||||
this.projects$.next([]);
|
||||
this.allProjects$.next([]);
|
||||
this.allProjectsCount$.next({allProjectsCount: 0});
|
||||
}
|
||||
this.loading$.next(false);
|
||||
},
|
||||
error: err => {
|
||||
|
@ -60,78 +100,50 @@ export class ProjectOverviewComponent implements OnInit {
|
|||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: false,
|
||||
autoFocus: true,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: ProjectDialogBody) => this.projectService.saveProject(value)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.save.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
this.notificationService.showPopup('project.popup.save.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickEditProject(project: Project): void {
|
||||
this.projectDialogService.openProjectDialog(
|
||||
ProjectDialogComponent,
|
||||
project,
|
||||
{
|
||||
closeOnEsc: false,
|
||||
hasScroll: false,
|
||||
autoFocus: false,
|
||||
closeOnBackdropClick: false
|
||||
}
|
||||
).pipe(
|
||||
filter(value => !!value),
|
||||
mergeMap((value: ProjectDialogBody) => this.projectService.updateProject(project.id, value)),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.update.success', PopupType.SUCCESS);
|
||||
},
|
||||
error: error => {
|
||||
console.error(error);
|
||||
this.notificationService.showPopup('project.popup.update.failed', PopupType.FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onClickDeleteProject(project: Project): void {
|
||||
const message = {
|
||||
title: 'project.delete.title',
|
||||
key: 'project.delete.key',
|
||||
data: {name: project.title},
|
||||
};
|
||||
this.dialogService.openConfirmDialog(
|
||||
message
|
||||
).onClose.pipe(
|
||||
filter((confirm) => !!confirm),
|
||||
switchMap(() => this.projectService.deleteProjectById(project.id)),
|
||||
catchError(() => {
|
||||
this.notificationService.showPopup('project.popup.delete.failed', PopupType.FAILURE);
|
||||
return [];
|
||||
}),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: () => {
|
||||
this.loadProjects();
|
||||
this.notificationService.showPopup('project.popup.delete.success', PopupType.SUCCESS);
|
||||
}, error: error => {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// HTML only
|
||||
isLoading(): Observable<boolean> {
|
||||
return this.loading$.asObservable();
|
||||
}
|
||||
|
||||
onClickResetFilter(): void {
|
||||
this.projectSearch.reset('');
|
||||
this.projects$.next(this.allProjects$.getValue());
|
||||
}
|
||||
|
||||
private setFilterObserverForProjects(): void {
|
||||
this.filter$ = this.projectSearch.valueChanges.pipe(startWith(''));
|
||||
this.filter$.subscribe(
|
||||
(filterString: string) => {
|
||||
if (filterString.length === 0) {
|
||||
this.projects$.next(this.allProjects$.getValue());
|
||||
} else {
|
||||
const matchingProjects: Project[] = [];
|
||||
this.allProjects$.getValue().forEach(project => {
|
||||
// Project attributes that the user can filter through
|
||||
if (
|
||||
project.title.toLowerCase().includes(filterString.toLowerCase())
|
||||
|| project.client.toLowerCase().includes(filterString.toLowerCase())
|
||||
|| project.tester.toLowerCase().includes(filterString.toLowerCase())
|
||||
|| project.state.toString().toLowerCase().includes(filterString.toLowerCase())
|
||||
) {
|
||||
matchingProjects.push(project);
|
||||
}
|
||||
});
|
||||
this.projects$.next(matchingProjects);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,34 +2,55 @@ import {NgModule} from '@angular/core';
|
|||
import {CommonModule} from '@angular/common';
|
||||
import {ProjectOverviewComponent} from './project-overview.component';
|
||||
import {ProjectOverviewRoutingModule} from './project-overview-routing.module';
|
||||
import {NbButtonModule, NbCardModule, NbMenuModule, NbProgressBarModule, NbSidebarModule, NbSpinnerModule} from '@nebular/theme';
|
||||
import {
|
||||
NbButtonModule,
|
||||
NbCardModule,
|
||||
NbFormFieldModule,
|
||||
NbInputModule,
|
||||
NbLayoutModule,
|
||||
NbProgressBarModule,
|
||||
NbSelectModule
|
||||
} from '@nebular/theme';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {DateTimeFormatPipe} from '@shared/pipes/date-time-format.pipe';
|
||||
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
|
||||
import {LoadingSpinnerComponent} from '@shared/widgets/loading-spinner/loading-spinner.component';
|
||||
import {CommonAppModule} from '../common-app.module';
|
||||
import {ConfirmDialogModule} from '@shared/modules/confirm-dialog/confirm-dialog.module';
|
||||
import {SecurityConfirmDialogModule} from '@shared/modules/security-confirm-dialog/security-confirm-dialog.module';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {ReportStateTagModule} from '@shared/widgets/report-state-tag/report-state-tag.module';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {ProjectWidgetModule} from '@shared/widgets/project-widget/project-widget.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ProjectOverviewComponent,
|
||||
DateTimeFormatPipe,
|
||||
LoadingSpinnerComponent
|
||||
ProjectOverviewComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CommonAppModule,
|
||||
RouterModule.forChild([{
|
||||
path: '',
|
||||
component: ProjectOverviewComponent
|
||||
}]),
|
||||
NbCardModule,
|
||||
NbButtonModule,
|
||||
NbSpinnerModule,
|
||||
NbProgressBarModule,
|
||||
ProjectOverviewRoutingModule,
|
||||
FlexLayoutModule,
|
||||
FontAwesomeModule,
|
||||
TranslateModule,
|
||||
ProjectDialogModule
|
||||
],
|
||||
exports: [
|
||||
LoadingSpinnerComponent
|
||||
ProjectDialogModule,
|
||||
ConfirmDialogModule,
|
||||
ReportStateTagModule,
|
||||
SecurityConfirmDialogModule,
|
||||
NbLayoutModule,
|
||||
NbInputModule,
|
||||
NbFormFieldModule,
|
||||
ReactiveFormsModule,
|
||||
NbSelectModule,
|
||||
ProjectWidgetModule
|
||||
]
|
||||
})
|
||||
export class ProjectOverviewModule {
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {ProjectComponent} from './project.component';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ProjectComponent
|
||||
},
|
||||
{
|
||||
path: 'pentest',
|
||||
loadChildren: () => import('../../pentest-overview/pentest').then(mod => mod.PentestModule),
|
||||
path: Route.PENTEST_OBJECTIVE,
|
||||
loadChildren: () => import('../../pentest').then(mod => mod.PentestModule),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
<nb-layout fxFlex>
|
||||
|
||||
<nb-layout-header fxFlex="0 1 max-content" class="header-column">
|
||||
<app-pentest-header></app-pentest-header>
|
||||
<app-objective-header></app-objective-header>
|
||||
</nb-layout-header>
|
||||
|
||||
<nb-layout-column fxFlex="0 1 max-content" class="column-wrapper">
|
||||
<nb-card class="categories-column">
|
||||
<app-pentest-categories></app-pentest-categories>
|
||||
<app-objective-categories></app-objective-categories>
|
||||
</nb-card>
|
||||
</nb-layout-column>
|
||||
|
||||
<nb-layout-column fxFlex="0 1 max-content" class="table-wrapper" >
|
||||
<nb-layout-column fxFlex=" max-content" class="table-wrapper" >
|
||||
<nb-card class="table-column">
|
||||
<nb-card-body>
|
||||
<app-pentest-table></app-pentest-table>
|
||||
<app-objective-table></app-objective-table>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
</nb-layout-column>
|
||||
|
|
|
@ -8,22 +8,24 @@
|
|||
|
||||
.header-column {
|
||||
width: 100vw;
|
||||
height: $pentest-header-height;
|
||||
}
|
||||
|
||||
.column-wrapper {
|
||||
padding-left: 0 !important;
|
||||
|
||||
.categories-column {
|
||||
height: calc(100vh - #{$pentest-header-height});
|
||||
height: calc(100vh - #{$pentest-header-height} - #{$header-height});
|
||||
}
|
||||
}
|
||||
|
||||
.table-wrapper{
|
||||
padding-right: 0 !important;
|
||||
border-style: none;
|
||||
|
||||
.table-column {
|
||||
overflow: auto !important;
|
||||
height: calc(100vh - #{$pentest-header-height});
|
||||
height: calc(100vh - #{$pentest-header-height} - #{$header-height});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,66 @@ import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
|||
import {HttpLoaderFactory} from '../../common-app.module';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {NgxsModule} from '@ngxs/store';
|
||||
import {SessionState} from '@shared/stores/session-state/session-state';
|
||||
import {NgxsModule, Store} from '@ngxs/store';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {NbCardModule, NbLayoutModule} from '@nebular/theme';
|
||||
import {NbCardModule, NbDialogRef, NbLayoutModule} from '@nebular/theme';
|
||||
import {KeycloakService} from 'keycloak-angular';
|
||||
import {PentestOverviewModule} from '../../pentest-overview';
|
||||
import {ObjectiveOverviewModule} from '../../objective-overview';
|
||||
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||
import {ProjectService} from '@shared/services/api/project.service';
|
||||
import {ProjectServiceMock} from '@shared/services/api/project.service.mock';
|
||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
||||
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||
import {Category} from '@shared/models/category.model';
|
||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||
import {createSpyObj} from '@shared/modules/finding-dialog/finding-dialog.component.spec';
|
||||
import {ExportReportDialogService} from '@shared/modules/export-report-dialog/service/export-report-dialog.service';
|
||||
import {ExportReportDialogServiceMock} from '@shared/modules/export-report-dialog/service/export-report-dialog.service.mock';
|
||||
import {ReportState} from '@shared/models/state.enum';
|
||||
|
||||
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||
allProjects: [],
|
||||
selectedProject: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
|
||||
client: 'E Corp',
|
||||
title: 'Some Mock API (v1.0) Scanning',
|
||||
createdAt: new Date('2019-01-10T09:00:00'),
|
||||
tester: 'Novatester',
|
||||
summary: '',
|
||||
state: ReportState.NEW,
|
||||
version: '1.0',
|
||||
testingProgress: 0,
|
||||
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
|
||||
},
|
||||
// Manages Categories
|
||||
disabledCategories: [],
|
||||
selectedCategory: Category.INFORMATION_GATHERING,
|
||||
// Manages Pentests of Category
|
||||
disabledPentests: [],
|
||||
selectedPentest: {
|
||||
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
|
||||
category: Category.INFORMATION_GATHERING,
|
||||
refNumber: 'OTF-001',
|
||||
childEntries: [],
|
||||
status: PentestStatus.NOT_STARTED,
|
||||
enabled: true,
|
||||
findingIds: [],
|
||||
commentIds: ['56c47c56-3bcd-45f1-a05b-c197dbd33112']
|
||||
},
|
||||
};
|
||||
|
||||
describe('ProjectComponent', () => {
|
||||
let component: ProjectComponent;
|
||||
let fixture: ComponentFixture<ProjectComponent>;
|
||||
let store: Store;
|
||||
|
||||
beforeEach(async () => {
|
||||
const dialogSpy = createSpyObj('NbDialogRef', ['close']);
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
ProjectComponent
|
||||
|
@ -27,7 +75,7 @@ describe('ProjectComponent', () => {
|
|||
CommonModule,
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
PentestOverviewModule,
|
||||
ObjectiveOverviewModule,
|
||||
ThemeModule.forRoot(),
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
|
@ -37,12 +85,18 @@ describe('ProjectComponent', () => {
|
|||
}
|
||||
}),
|
||||
RouterTestingModule.withRoutes([]),
|
||||
NgxsModule.forRoot([SessionState]),
|
||||
NgxsModule.forRoot([ProjectState]),
|
||||
HttpClientModule,
|
||||
HttpClientTestingModule
|
||||
],
|
||||
providers: [
|
||||
KeycloakService
|
||||
KeycloakService,
|
||||
{provide: ProjectService, useValue: new ProjectServiceMock()},
|
||||
{provide: DialogService, useClass: DialogServiceMock},
|
||||
{provide: NbDialogRef, useValue: dialogSpy},
|
||||
{provide: ExportReportDialogService, useClass: ExportReportDialogServiceMock},
|
||||
{provide: ProjectDialogService, useClass: ProjectDialogServiceMock},
|
||||
{provide: NotificationService, useClass: NotificationServiceMock}
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
@ -50,6 +104,11 @@ describe('ProjectComponent', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProjectComponent);
|
||||
store = TestBed.inject(Store);
|
||||
store.reset({
|
||||
...store.snapshot(),
|
||||
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
|
||||
});
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {InitProjectState} from '@shared/stores/project-state/project-state.actions';
|
||||
import {Router} from '@angular/router';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||
import {Route} from '@shared/models/route.enum';
|
||||
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||
import {Project} from '@shared/models/project.model';
|
||||
|
||||
@UntilDestroy()
|
||||
|
@ -20,19 +20,23 @@ export class ProjectComponent implements OnInit {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (history?.state && 'selectedProject' in history?.state) {
|
||||
this.initProjectStore();
|
||||
} else {
|
||||
this.router.navigate([Route.PROJECT_OVERVIEW]).finally();
|
||||
}
|
||||
this.store.select(ProjectState.project).pipe(
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (selectedProject: Project) => {
|
||||
this.initProjectStore();
|
||||
},
|
||||
error: err => {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initProjectStore(): void {
|
||||
const project: Project = history?.state?.selectedProject ? history?.state?.selectedProject : null;
|
||||
this.store.dispatch(new InitProjectState(
|
||||
project,
|
||||
[],
|
||||
[]
|
||||
)).pipe(untilDestroyed(this)).subscribe();
|
||||
this.router.navigate([Route.OBJECTIVE_OVERVIEW]).then(() => {
|
||||
}, err => {
|
||||
this.router.navigate([Route.PROJECT_OVERVIEW]);
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,22 +2,20 @@ import {NgModule} from '@angular/core';
|
|||
import {CommonModule} from '@angular/common';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {ProjectComponent} from './project.component';
|
||||
import {NbCardModule, NbLayoutModule, NbMenuModule, NbSidebarModule} from '@nebular/theme';
|
||||
import {NbCardModule, NbLayoutModule} from '@nebular/theme';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
|
||||
import {ProjectRoutingModule} from './project-routing.module';
|
||||
import {PentestOverviewModule} from '../../pentest-overview';
|
||||
import {ObjectiveOverviewModule} from '../../objective-overview';
|
||||
import {CommonAppModule} from '../../common-app.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ProjectComponent
|
||||
],
|
||||
exports: [
|
||||
ProjectComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
CommonAppModule,
|
||||
NbCardModule,
|
||||
NbLayoutModule,
|
||||
RouterModule.forChild([{
|
||||
|
@ -27,8 +25,10 @@ import {PentestOverviewModule} from '../../pentest-overview';
|
|||
ProjectRoutingModule,
|
||||
TranslateModule,
|
||||
FlexLayoutModule,
|
||||
ProjectDialogModule,
|
||||
PentestOverviewModule
|
||||
ObjectiveOverviewModule
|
||||
],
|
||||
exports: [
|
||||
ProjectComponent
|
||||
]
|
||||
})
|
||||
export class ProjectModule {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.dialog-header {
|
||||
height: 6.75vh;
|
||||
height: 6.75vh !important;
|
||||
font-size: 1.5rem;
|
||||
|
||||
.dialog-headline {
|
||||
|
@ -8,11 +8,13 @@
|
|||
}
|
||||
|
||||
.dialog-body {
|
||||
font-size: 1.15rem;
|
||||
font-size: 1rem;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.dialog-button {
|
||||
width: 5.25rem;
|
||||
height: 2.5rem;
|
||||
// font-size: 0.85rem;
|
||||
width: 5.75rem !important;
|
||||
height: 2.15rem !important;
|
||||
text-transform: none !important;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/* mixin for multiline */
|
||||
@mixin multiLineEllipsis($font-size, $font-weight, $line-height, $lines-to-show, $max-width) {
|
||||
// Fallback for non-webkit
|
||||
display: block;
|
||||
display: -webkit-box;
|
||||
max-width: $max-width;
|
||||
// Fallback for non-webkit
|
||||
height: calc(#{$font-size} * #{$line-height} * #{$lines-to-show});
|
||||
font-size: $font-size;
|
||||
font-weight: $font-weight;
|
||||
line-height: $line-height;
|
||||
-webkit-line-clamp: $lines-to-show;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
|
@ -2,13 +2,17 @@
|
|||
@import 'themes';
|
||||
|
||||
// framework component themes (styles tied to theme variables)
|
||||
@import '~@nebular/theme/styles/globals';
|
||||
@import '@nebular/theme/styles/globals';
|
||||
|
||||
// loading progress bar theme
|
||||
@import './pace.theme';
|
||||
@import './overrides';
|
||||
@import './variables';
|
||||
|
||||
// loading glide
|
||||
@import "@glidejs/glide/src/assets/sass/glide.core";
|
||||
@import "@glidejs/glide/src/assets/sass/glide.theme";
|
||||
|
||||
* {
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @nebular theming framework
|
||||
@import '~@nebular/theme/styles/theming';
|
||||
@import '@nebular/theme/styles/theming';
|
||||
// @nebular out of the box themes
|
||||
@import '~@nebular/theme/styles/themes';
|
||||
@import '@nebular/theme/styles/themes';
|
||||
// enable custom css properties
|
||||
$nb-enable-css-custom-properties: true;
|
||||
|
||||
|
|
|
@ -1,17 +1,40 @@
|
|||
{
|
||||
"global": {
|
||||
"actions": "Aktionen",
|
||||
"action.profile": "Profil",
|
||||
"action.login": "Einloggen",
|
||||
"action.logout": "Ausloggen",
|
||||
"action.retry": "Erneut Versuchen",
|
||||
"action.info": "Info",
|
||||
"action.save": "Speichern",
|
||||
"action.confirm": "Bestätigen",
|
||||
"action.cancel": "Abbrechen",
|
||||
"action.return": "Zurück",
|
||||
"action.exit": "Beenden",
|
||||
"action.update": "Speichern",
|
||||
"action.edit": "Editieren",
|
||||
"action.export": "Exportieren",
|
||||
"action.download": "Herunterladen",
|
||||
"action.report": "Bericht",
|
||||
"action.reset": "Zurücksetzen",
|
||||
"action.complete": "Fertig",
|
||||
"action.disable": "Deaktivieren",
|
||||
"action.enable": "Aktivieren",
|
||||
"action.close": "Schließen",
|
||||
"action.yes": "Ja",
|
||||
"action.no": "Nein",
|
||||
"username": "Nutzername",
|
||||
"password": "Passwort"
|
||||
"password": "Passwort",
|
||||
"no.progress": "Kein Fortschritt",
|
||||
"project": "Projekt",
|
||||
"version": "Version",
|
||||
"validationMessage": {
|
||||
"inputNotMatching": "Eingabe stimmt nicht überein!"
|
||||
},
|
||||
"retry.dialog": {
|
||||
"title": "Etwas ist schief gelaufen...",
|
||||
"information": "Fehler beim verarbeiten Ihrer Anfrage. \nBitte versuchen Sie es erneut oder zu einem späteren Zeitpunkt."
|
||||
}
|
||||
},
|
||||
"languageKeys":{
|
||||
"de-DE": "Deutsch",
|
||||
|
@ -35,18 +58,105 @@
|
|||
"failed": "Benutzername oder Passwort falsch",
|
||||
"unauthorized": "Benutzer nicht gefunden. Bitte registrieren und erneut versuchen"
|
||||
},
|
||||
"profile": {
|
||||
"header": "Nutzerprofil",
|
||||
"username": {
|
||||
"title": "Nutzername",
|
||||
"placeholder": "Nutzername"
|
||||
},
|
||||
"firstName": {
|
||||
"title": "Vorname",
|
||||
"placeholder": "Vorname"
|
||||
},
|
||||
"lastName": {
|
||||
"title": "Nachname",
|
||||
"placeholder": "Nachname"
|
||||
},
|
||||
"eMail": {
|
||||
"title": "E-Mail",
|
||||
"placeholder": "Keine E-Mail bestätigt."
|
||||
},
|
||||
"validationMessage": {
|
||||
"firstNameRequired": "Vorname ist erforderlich.",
|
||||
"lastNameRequired": "Nachname ist erforderlich."
|
||||
},
|
||||
"languageLabel": "Sprache ändern:",
|
||||
"password": {
|
||||
"title": "Passwort ändern:",
|
||||
"button" : "Passwort ändern",
|
||||
"old": "Altes Passwort",
|
||||
"new": "Neues Passwort",
|
||||
"confirmNew": "Neues Passwort bestätigen",
|
||||
"validationMessage": {
|
||||
"passwordRequired": "Passwort ist erforderlich."
|
||||
}
|
||||
}
|
||||
},
|
||||
"tutorial": {
|
||||
"header": "Erste Schritte mit C4PO",
|
||||
"carousel": {
|
||||
"project_overview": "Die Projektübersicht gibt Ihnen einen Überblick über alle Ihre aktuellen Projekte.\nHier können Sie neue erstellen, bestehende bearbeiten oder löschen oder nach einem bestimmten Projekt filtern.\nSehen Sie den aktuellen Stand Ihrer Projekte sowie den Fortschritt zusammen mit einigen zusätzlichen Informationen wie Name, Kunde, Tester und wann es erstellt wurde.",
|
||||
"project_overview_filtered": "Das Filtern in der Projektübersicht kann Ihnen helfen, das/die gesuchte(n) Projekt(e) zu finden.\nGeben Sie bestimmte Schlüsselwörter wie den Titel eines Projekts oder einen speziellen Status wie „Benötigt weitere Informationen“ ein oder suchen Sie nach einem wichtigen Kunden.",
|
||||
"create_edit_project": "Erstellen Sie ein neues oder ein bestehendes Projekt, geben Sie ihm einen Titel und einen Kundennamen, weisen Sie einen Tester zu und schreiben Sie eine Zusammenfassung für den Pentest (nur im Bearbeitungsmodus verfügbar).\nDarüber hinaus können Sie auch einen bestimmten Status für das Projekt auswählen, um anzuzeigen, ob der Pentest derzeit „in Arbeit“ ist oder darauf wartet, dass der Kunde den Bericht überprüft.",
|
||||
"userprofile": "Ändern Sie Ihre Einstellungen.\nEgal, ob Sie nur die Sprache der Anwendung auswählen oder Ihr Passwort ändern.",
|
||||
"category&objective_overview": "Sehen Sie sich hier jedes Ziel jeder Kategorie an.\nDerselbe Inhalt ist auch im OWASP Web Testing Guide enthalten.\nSie können sich einen guten Überblick über alle Ziele verschaffen, die in einer bestimmten Kategorie enthalten sind, sehen, wie viele Ergebnisse und Kommentare hinzugefügt wurden, und sogar bestimmte Ziele deaktivieren, was zur Folge hat, dass sie nicht in den Bericht aufgenommen werden.",
|
||||
"objective_info": "Lesen Sie die wichtigsten Informationen zum gewählten Ziel.\nZu diesen Informationen gehört, was am Ziel zu tun ist, welche Probleme am häufigsten auftreten und wie Sie sie ausnutzen können.",
|
||||
"objective_finding_overview": "Sehen Sie sich alle Funde an, die sich auf das ausgewählte Ziel beziehen.\nSie können den Titel, den Schweregrad, einen Teil der Beschreibung und die Auswirkung des Befundes sehen.\nDarüber hinaus können Sie einen bestimmten Befund auch bearbeiten oder sogar löschen.",
|
||||
"create_edit_finding": "Bearbeiten oder erstellen Sie neue Funde für das Ziel.\nDokumentieren Sie hier den Titel, die Beschreibung, die betroffenen Anwendungsteile, die betroffenen URLs oder APIs und eine Schweregradbewertung zusammen mit Reproduktionsschritten und einem Abhilfevorschlag.\nSie können Befunde erst erstellen, wenn Sie den Timer gestartet haben, damit Ihre Arbeit nachverfolgt wird.",
|
||||
"objective_comment_overview": "Sehen Sie sich alle Kommentare an, die sich auf das ausgewählte Ziel beziehen.\nSie können den Titel und einen Teil der Beschreibung des Kommentars sehen.\nDarüber hinaus können Sie einen bestimmten Kommentar auch bearbeiten oder sogar löschen.",
|
||||
"create_edit_comment": "Bearbeiten oder erstellen Sie neue Kommentare für das Ziel.\nDokumentieren Sie hier den Titel und eine Beschreibung.\nSie können Kommentare erst erstellen, wenn Sie den Timer gestartet haben, damit Ihre Arbeit nachverfolgt wird.",
|
||||
"generate_report": "Generieren und exportieren Sie Ihren Bericht. Sie können den Namen und die Version Ihres Projekts sowie einige Statistiken darüber sehen, wie viele Ihrer Ziele abgeschlossen, in Bearbeitung, pausiert, nicht gestartet oder deaktiviert sind.\nNur Ihre abgeschlossenen Ziele werden in den Abschlussbericht aufgenommen.\nStellen Sie vor dem Exportieren sicher, dass Sie die richtige Sprache für Ihren Bericht auswählen.",
|
||||
"report": "Laden Sie Ihren generierten Bericht als PDF herunter und senden Sie ihn direkt an den Kunden.\nDer Bericht enthält alle Informationen, die Sie in der C4PO-Anwendung eingegeben haben.\nDer Bericht besteht aus einem Deckblatt, einem Inhaltsverzeichnis, dem Stand der Vertraulichkeit, einer Zusammenfassung, technischen Details zu den Ergebnissen sowie Kommentaren und Anhängen."
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
"new": "Neu",
|
||||
"needs_more_info": "Benötigt mehr Informationen",
|
||||
"pre_submission": "Voranmeldung",
|
||||
"pending": "Pending",
|
||||
"triaged": "Ausstehend",
|
||||
"retesting": "Erneutes Testen",
|
||||
"resolved": "Aufgeklärt",
|
||||
"informative": "Informativ",
|
||||
"duplicate": "Duplikat",
|
||||
"not_applicable": "Unzutreffend",
|
||||
"spam": "Spam",
|
||||
"out_of_scope": "Außerhalb Anwendungsbereich",
|
||||
"accepted_risk": "Akzeptiertes Risiko"
|
||||
},
|
||||
"report": {
|
||||
"dialog": {
|
||||
"header": "Penetrationstestbereicht exportieren",
|
||||
"formatLabel": "Wählen Sie das Exportformat für den Bericht:",
|
||||
"languageLabel": "Wählen Sie die Berichtssprache:"
|
||||
},
|
||||
"popup": {
|
||||
"generation.success": "Bericht erfolgreich generiert",
|
||||
"generation.failed": "Bericht konnte nicht generiert werden"
|
||||
},
|
||||
"generate": "Bericht generieren",
|
||||
"hint": "{{completedObjectivesNumber}} Ihrer abgeschlossenen Ziele wird in den Pentestbericht aufgenommen."
|
||||
},
|
||||
"project": {
|
||||
"title.label": "Projekt Titel",
|
||||
"client.label": "Name des Auftraggebers",
|
||||
"tester.label": "Name des Pentester",
|
||||
"state.label": "Penteststatus",
|
||||
"summary.label": "Zusammenfassung",
|
||||
"summary.placeholder": "Sollte eine Zusammenfassung, einen Ansatz, einen Umfang und eine Bewertungsübersicht sowie allgemeine Empfehlungen enthalten",
|
||||
"title": "Titel",
|
||||
"client": "Klient",
|
||||
"tester": "Tester",
|
||||
"state": "Penteststatus",
|
||||
"summary": "Zusammenfassung",
|
||||
"createdAt": "Erstellt am",
|
||||
"overview": {
|
||||
"add.project": "Projekt hinzufügen",
|
||||
"no.projects": "Keine Projekte verfügbar"
|
||||
},
|
||||
"filter": {
|
||||
"placeholder": "Alle {{allProjectsCount}} Projekt(e) durchsuchen.."
|
||||
},
|
||||
"create": {
|
||||
"header": "Neues Projekt erstellen"
|
||||
},
|
||||
|
@ -55,12 +165,16 @@
|
|||
},
|
||||
"delete": {
|
||||
"title": "Projekt löschen",
|
||||
"key": "Möchten Sie das Projekt \"{{name}}\" unwiderruflich löschen?"
|
||||
"key": "Möchten Sie das Projekt \"{{name}}\" unwiderruflich löschen?",
|
||||
"confirmStringPlaceholder": "Geben Sie zur Bestätigung den Projekttitel ein",
|
||||
"sec.key": "Möchten Sie das Projekt \"{{name}}\" unwiderruflich löschen? \nSie löschen damit auch alle zugehörigen Daten."
|
||||
},
|
||||
"validationMessage": {
|
||||
"titleRequired": "Titel ist erforderlich.",
|
||||
"clientRequired": "Klient ist erforderlich.",
|
||||
"testerRequired": "Tester ist erforderlich."
|
||||
"testerRequired": "Tester ist erforderlich.",
|
||||
"stateRequired": "Status ist erforderlich.",
|
||||
"summaryRequired": "Zusammenfassung ist erforderlich."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "Keine Projekte gefunden",
|
||||
|
@ -72,20 +186,155 @@
|
|||
"delete.failed": "Projekt konnte nicht gelöscht werden"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"INFORMATION_GATHERING": "Informationsbeschaffung",
|
||||
"CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING": "Konfig- & Einsatzmanagement-Testing",
|
||||
"IDENTITY_MANAGEMENT_TESTING": "Identitätsmanagement-Testing",
|
||||
"AUTHENTICATION_TESTING": "Authentifizierungs-Testing",
|
||||
"AUTHORIZATION_TESTING": "Autorisations-Testing",
|
||||
"SESSION_MANAGEMENT_TESTING": "Sitzungsmanagement-Testing",
|
||||
"INPUT_VALIDATION_TESTING": "Eingabevalidierungs-Testing",
|
||||
"ERROR_HANDLING": "Fehlerbehandlung",
|
||||
"CRYPTOGRAPHY": "Kryptographie",
|
||||
"BUSINESS_LOGIC_TESTING": "Business-Logik-Testing",
|
||||
"CLIENT_SIDE_TESTING": "Clientseitiges-Testing",
|
||||
"API_TESTING": "API Testing"
|
||||
},
|
||||
"finding": {
|
||||
"findingId": "Fund Id",
|
||||
"severity": "Schwere",
|
||||
"title": "Titel",
|
||||
"description": "Beschreibung",
|
||||
"impact": "Auswirkung",
|
||||
"affectedUrls": "Betroffene URL's / API's",
|
||||
"reproduction": "Reproduktion",
|
||||
"mitigation": "Minderung",
|
||||
"add": "Fund hinzufügen",
|
||||
"add.url": "Betroffene URL / API hinzufügen",
|
||||
"affectedUrls.placeholder": "Betroffene URL oder API hier eingeben..",
|
||||
"create": {
|
||||
"header": "Neuen Fund erstellen"
|
||||
},
|
||||
"edit": {
|
||||
"header": "Fund editieren"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Fund löschen",
|
||||
"key": "Möchten Sie den Fund \"{{name}}\" unwiderruflich löschen?"
|
||||
},
|
||||
"severity.label": "Schwere des Funds",
|
||||
"title.label": "Fundtitel",
|
||||
"description.label": "Beschreibung des Funds",
|
||||
"impact.label": "Auswirkung auf Anwendung",
|
||||
"affectedUrls.label": "Betroffene URL's / API's",
|
||||
"reproduction.label": "Reproduktionsschritte",
|
||||
"mitigation.label": "Minderungsvorschlag",
|
||||
"no.findings": "Keine Funde verfügbar",
|
||||
"validationMessage": {
|
||||
"titleRequired": "Titel ist erforderlich.",
|
||||
"severityRequired": "Schwere ist erforderlich.",
|
||||
"descriptionRequired": "Beschreibung ist erforderlich.",
|
||||
"impactRequired": "Auswirkung ist erforderlich.",
|
||||
"affectedUrlsRequired": "Betroffene URL's erforderlich.",
|
||||
"reproductionRequired": "Reproduktionschritt(e) sind erforderlich.",
|
||||
"mitigationRequired": "Minderungsvorschlag ist erforderlich."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "Keine Funde gefunden",
|
||||
"save.success": "Fund erfolgreich gespeichert",
|
||||
"save.failed": "Fund konnte nicht gespeichert werden",
|
||||
"update.success": "Fund erfolgreich aktualisiert",
|
||||
"update.failed": "Fund konnte nicht aktualisiert werden",
|
||||
"delete.success": "Fund erfolgreich gelöscht",
|
||||
"delete.failed": "Fund konnte nicht gelöscht werden",
|
||||
"not.available": "Fund ist nicht mehr verfügbar"
|
||||
}
|
||||
},
|
||||
"severities": {
|
||||
"low": "Niedrig",
|
||||
"medium": "Mittel",
|
||||
"high": "Hoch",
|
||||
"critical": "Kritisch"
|
||||
},
|
||||
"comment": {
|
||||
"commentId": "Kommentar Id",
|
||||
"title": "Titel",
|
||||
"description": "Beschreibung",
|
||||
"relatedFindings": "Verbundene Funde",
|
||||
"add": "Kommentar hinzufügen",
|
||||
"add.finding": "Fund hinzufügen",
|
||||
"no.comments": "Keine Kommentare verfügbar",
|
||||
"no.relatedFindings": "Nicht verbunden mit einem Fund",
|
||||
"relatedFindingsPlaceholder": "Fund auswählen",
|
||||
"noFindingsInObjectivePlaceholder": "Ziel hat keine Befunde, auf die es sich beziehen könnte.",
|
||||
"create": {
|
||||
"header": "Neuen Kommentar erstellen"
|
||||
},
|
||||
"edit": {
|
||||
"header": "Kommentar editieren"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Kommentar löschen",
|
||||
"key": "Möchten Sie den Kommentar \"{{name}}\" unwiderruflich löschen?"
|
||||
},
|
||||
"title.label": "Kommentartitel",
|
||||
"description.label": "Beschreibung des Kommentars",
|
||||
"relatedFindings.label": "Verbundene Funde",
|
||||
"validationMessage": {
|
||||
"titleRequired": "Titel ist erforderlich.",
|
||||
"descriptionRequired": "Beschreibung ist erforderlich.",
|
||||
"relatedFindings": "Verwandte Funde erforderlich."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "Keine Kommentare gefunden",
|
||||
"save.success": "Kommentar erfolgreich gespeichert",
|
||||
"save.failed": "Kommentar konnte nicht gespeichert werden",
|
||||
"update.success": "Kommentar erfolgreich aktualisiert",
|
||||
"update.failed": "Kommentar konnte nicht aktualisiert werden",
|
||||
"delete.success": "Kommentar erfolgreich gelöscht",
|
||||
"delete.failed": "Kommentar konnte nicht gelöscht werden",
|
||||
"not.available": "Kommentar ist nicht mehr verfügbar"
|
||||
}
|
||||
},
|
||||
"pentest": {
|
||||
"testId": "Nr.",
|
||||
"title": "Titel",
|
||||
"findings": "Funde",
|
||||
"comments": "Kommentare",
|
||||
"findings&comments": "Funde & Kommentare",
|
||||
"status": "Status",
|
||||
"statusText": {
|
||||
"not_started": "Nicht angefangen",
|
||||
"disabled": "Deaktiviert",
|
||||
"open": "Offen",
|
||||
"checked": "Geprüft",
|
||||
"reported": "Gemeldet",
|
||||
"under_review": "Unter Beurteilung",
|
||||
"triaged": "Triagiert"
|
||||
"paused": "Pausiert",
|
||||
"in_progress": "In Bearbeitung",
|
||||
"completed": "Fertig"
|
||||
},
|
||||
"disable": {
|
||||
"title": "Ziel deaktivieren",
|
||||
"key": "Möchten Sie den Pentest \"{{name}}\" deaktivieren?"
|
||||
},
|
||||
"enable": {
|
||||
"title": "Ziel aktivieren",
|
||||
"key": "Möchten Sie den Pentest \"{{name}}\" aktivieren?"
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "Keine pentests gefunden",
|
||||
"initial.save.success": "Initialer Pentest erfolgreich aufgesetzt",
|
||||
"initial.save.failed": "Initialer Pentest konnte nicht aufgesetzt werden",
|
||||
"save.success": "Pentest erfolgreich gespeichert",
|
||||
"save.failed": "Pentest konnte nicht gespeichert werden",
|
||||
"complete.success": "Pentest erfolgreich vervollständigt",
|
||||
"complete.failed": "Pentest konnte nicht vervollständigt werden",
|
||||
"update.success": "Pentest erfolgreich aktualisiert",
|
||||
"update.failed": "Pentest konnte nicht aktualisiert werden",
|
||||
"delete.success": "Pentest erfolgreich gelöscht",
|
||||
"delete.failed": "Pentest konnte nicht gelöscht werden",
|
||||
"disable.success": "Ziel erfolgreich deaktiviert",
|
||||
"disable.failed": "Ziel konnte nicht deaktiviert werden",
|
||||
"enable.success": "Ziel erfolgreich aktiviert",
|
||||
"enable.failed": "Ziel konnte nicht aktiviert werden"
|
||||
},
|
||||
"info": {
|
||||
"001": "Nutze Suchmaschinenerkennung und -aufklärung für Informationslecks",
|
||||
|
@ -93,7 +342,7 @@
|
|||
"003": "Prüfe Webserver-Metadateien auf Informationslecks",
|
||||
"004": "Anwendungen auf dem Webserver auflisten",
|
||||
"005": "Prüfe Webseitenkommentare und Metadaten auf Informationslecks",
|
||||
"006": "Einstiegspunkte für Identitätsanträge",
|
||||
"006": "Identifizieren der Einstiegspunkte",
|
||||
"007": "Zuordnen von Ausführungspfade der Anwendung",
|
||||
"008": "Framework für Fingerabdruck-Webanwendungen",
|
||||
"009": "Fingerabdruck-Webanwendungen",
|
||||
|
@ -103,20 +352,21 @@
|
|||
"001": "Netzwerk-/Infrastrukturkonfiguration testen",
|
||||
"002": "Testen Sie die Konfiguration der Anwendungsplattform",
|
||||
"003": "Testen der Behandlung von Dateierweiterungen für vertrauliche Informationen",
|
||||
"004": "Backup und nicht referenzierte Dateien für sensible Informationen",
|
||||
"004": "Prüfen von Backups und Dateien für sensible Informationen",
|
||||
"005": "Aufzählen der Infrastruktur- und Anwendungsverwaltungsschnittstellen",
|
||||
"006": "HTTP-Methoden testen",
|
||||
"007": "Testen Sie HTTP Strict Transport Security",
|
||||
"008": "Testen der domänenübergreifende RIA-Richtlinie"
|
||||
"008": "Testen der domänenübergreifende RIA-Richtlinie",
|
||||
"009": "Dateiberechtigung testen",
|
||||
"010": "Test auf Subdomain-Übernahme",
|
||||
"011": "Cloud-Speicher testen"
|
||||
},
|
||||
"ident": {
|
||||
"001": "Rollendefinitionen testen",
|
||||
"002": "Registrierungsprozess testen",
|
||||
"003": "Konto-Bereitstellungsprozess testen",
|
||||
"004": "Testen auf Kontoaufzählung und erratbares Benutzerkonto",
|
||||
"005": "Test auf schwache oder nicht erzwungene Richtlinie für Benutzernamen",
|
||||
"006": "Testberechtigungen von Gast-/Schulungskonten",
|
||||
"007": "Sperrung/Wiederaufnahme des Kontos testen"
|
||||
"005": "Test auf schwache oder nicht erzwungene Richtlinie für Benutzernamen"
|
||||
},
|
||||
"authn": {
|
||||
"001": "Testen auf Anmeldeinformationen, die über einen verschlüsselten Kanal transportiert werden",
|
||||
|
@ -144,45 +394,49 @@
|
|||
"005": "Prüfung auf Cross-Site-Request-Forgery",
|
||||
"006": "Testen der Abmeldefunktion",
|
||||
"007": "Testen der Sitzungszeitüberschreitung",
|
||||
"008": "Testen auf Session-Rätsel"
|
||||
"008": "Testen auf Session-Puzzle",
|
||||
"009": "Testen auf Session Hijacking"
|
||||
},
|
||||
"inpval": {
|
||||
"001": "Testen auf reflektiertes Cross-Site-Scripting",
|
||||
"002": "Testen auf konserviertes Cross Site Scripting",
|
||||
"001": "Testen auf Reflected Cross-Site-Scripting",
|
||||
"002": "Testen auf Stored Cross-Site-Scripting",
|
||||
"003": "Testen auf HTTP-Verb-Manipulation",
|
||||
"004": "Prüfung auf HTTP-Parameterverschmutzung",
|
||||
"005": "N/A",
|
||||
"006": "Testen auf SQL-Injection",
|
||||
"006_1": "Oracle-Tests",
|
||||
"006_2": "SQL Server-Tests",
|
||||
"006_3": "Testen von PostgreSQL",
|
||||
"006_4": "MS-Access-Tests",
|
||||
"006_5": "Testen auf NoSQL-Injection",
|
||||
"007": "Testen auf LDAP-Injection",
|
||||
"008": "Prüfung auf ORM-Injection",
|
||||
"009": "Testen auf XML-Injection",
|
||||
"010": "Prüfung auf SSI-Injection",
|
||||
"011": "Testen auf XPath-Injection",
|
||||
"012": "IMAP/SMTP-Injection",
|
||||
"013": "Testen auf Code-Injection",
|
||||
"013_1": "Testen der lokalen Dateieinbindung",
|
||||
"013_2": "Testen der Remote-Dateieinbindung",
|
||||
"014": "Testen auf BefehlInjection",
|
||||
"015": "Test auf Pufferüberlauf",
|
||||
"015_1": "Test auf Heap-Überlauf",
|
||||
"015_2": "Test auf Stack-Überlauf",
|
||||
"015_3": "Testen auf Formatzeichenfolge",
|
||||
"016": "Testen auf inkubierte Schwachstellen",
|
||||
"017": "Testen auf HTTP-Splitting/-Schmuggel"
|
||||
"005": "Testen auf SQL-Injection",
|
||||
"005_1": "Oracle-Tests",
|
||||
"005_2": "MySQL-Tests",
|
||||
"005_3": "SQL Server-Tests",
|
||||
"005_4": "Testen von PostgreSQL",
|
||||
"005_5": "MS-Access-Tests",
|
||||
"005_6": "Testen auf NoSQL-Injection",
|
||||
"005_7": "Testen auf ORM-Injection",
|
||||
"005_8": "Testen für Clientseite",
|
||||
"006": "Testen auf LDAP-Injection",
|
||||
"007": "Testen auf XML-Injection",
|
||||
"008": "Prüfung auf SSI-Injection",
|
||||
"009": "Testen auf XPath-Injection",
|
||||
"010": "IMAP/SMTP-Injection",
|
||||
"011": "Testen auf Code-Injection",
|
||||
"011_1": "Testen der lokalen Dateieinbindung",
|
||||
"011_2": "Testen der Remote-Dateieinbindung",
|
||||
"012": "Testen auf Command Injection",
|
||||
"013": "Testen auf Format-String-Injection",
|
||||
"014": "Testen auf bestehende Schwachstellen",
|
||||
"015": "Testen auf HTTP-Splitting/-Smuggling",
|
||||
"016": "Testen auf eingehende HTTP-Anfragen",
|
||||
"017": "Testen auf Host-Header-Injection",
|
||||
"018": "Testen auf serverseitige Template-Injection",
|
||||
"019": "Testen auf serverseitige Request Forgery"
|
||||
},
|
||||
"err": {
|
||||
"001": "Analyse von Fehlercodes",
|
||||
"002": "Analyse von Stack-Traces"
|
||||
},
|
||||
"crypst": {
|
||||
"001": "Testen auf schwache SSL/TSL-Chiffren, unzureichenden Transportschichtschutz",
|
||||
"001": "Testen auf schwache SSL/TLS-Chiffren, unzureichenden Transportschichtschutz",
|
||||
"002": "Testen für Padding Oracle",
|
||||
"003": "Prüfung auf sensible Informationen, die über unverschlüsselte Kanäle gesendet werden"
|
||||
"003": "Prüfung auf sensible Informationen, die über unverschlüsselte Kanäle gesendet werden",
|
||||
"004": "Testing auf Schwache Verschlüsselung"
|
||||
},
|
||||
"buslogic": {
|
||||
"001": "Testen Sie die Datenvalidierung der Geschäftslogik",
|
||||
|
@ -207,21 +461,146 @@
|
|||
"009": "Test auf Clickjacking",
|
||||
"010": "Testen von WebSockets",
|
||||
"011": "Testen von Web-Messaging",
|
||||
"012": "Lokalen Speicher testen"
|
||||
"012": "Lokalen Speicher testen",
|
||||
"013": "Testen auf Cross-Site-Script-Integration"
|
||||
},
|
||||
"api": {
|
||||
"001": "Testen von GraphQL"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"INFORMATION_GATHERING": "Informationsbeschaffung",
|
||||
"CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING": "Konfig- & Einsatzmanagement-Testing",
|
||||
"IDENTITY_MANAGEMENT_TESTING": "Identitätsmanagement-Testing",
|
||||
"AUTHENTICATION_TESTING": "Authentifizierungs-Testing",
|
||||
"AUTHORIZATION_TESTING": "Autorisations-Testing",
|
||||
"SESSION_MANAGEMENT_TESTING": "Sitzungsmanagement-Testing",
|
||||
"INPUT_VALIDATION_TESTING": "Eingabevalidierungs-Testing",
|
||||
"ERROR_HANDLING": "Fehlerbehandlung",
|
||||
"CRYPTOGRAPHY": "Kryptographie",
|
||||
"BUSINESS_LOGIC_TESTING": "Business-Logik-Testing",
|
||||
"CLIENT_SIDE_TESTING": "Clientseitiges-Testing"
|
||||
"objectives": {
|
||||
"info": {
|
||||
"001": "Ziel ist es zu verstehen, welche sensiblen Design- und Konfigurationsinformationen der Anwendung, des Systems oder der Organisation direkt (auf der Website der Organisation) oder indirekt (auf der Website eines Drittanbieters) offengelegt werden.\n\n Es gibt direkte und indirekte Elemente der Suchmaschinenerkennung und -aufklärung.\n Direkte Methoden beziehen sich auf das Durchsuchen der Indizes und der zugehörigen Inhalte aus Caches.\n Indirekte Methoden beziehen sich auf das Sammeln vertraulicher Design- und Konfigurationsinformationen durch das Durchsuchen von Foren, Newsgroups und Ausschreibungswebsites.\n\n Verwenden Sie eine Suchmaschine, um nach Folgendem zu suchen:\n• Netzwerkdiagramme und -konfigurationen\n• Archivierte Beiträge und E-Mails von Administratoren oder anderen wichtigen Mitarbeitern\n• Anmeldeverfahren und Benutzernamenformate\n• Benutzernamen und Passwörter\n• Inhalt der Fehlermeldung\n• Entwicklungs-, Test-, UAT- und Staging-Versionen der Website",
|
||||
"002": "Das Ziel besteht darin, die Version und den Typ eines laufenden Webservers zu finden, um bekannte Schwachstellen und die geeigneten Exploits zu ermitteln, die während des Tests verwendet werden können.\n\n Webserver-Fingerprinting ist eine kritische Aufgabe für den Penetrationstester.\nDie Kenntnis der Version und des Typs eines laufenden Webservers ermöglicht es Testern, bekannte Schwachstellen und die geeigneten Exploits zu ermitteln, die während des Tests verwendet werden können.\n\n Es gibt heute mehrere verschiedene Anbieter und Versionen von Webservern auf dem Markt. Die Kenntnis des Typs des getesteten Webservers hilft erheblich beim Testprozess und kann auch den Verlauf des Tests verändern. Die einfachste und grundlegendste Art, einen Webserver zu identifizieren, besteht darin, sich das Serverfeld im HTTP-Antwortheader anzusehen.\n\n Indem der Tester weiß, wie jeder Webservertyp auf bestimmte Befehle reagiert, und diese Informationen in einer Fingerprint-Datenbank des Webservers speichert, kann ein Penetrationstester diese Befehle an den Webserver senden, die Antwort analysieren und sie mit der Datenbank bekannter Signaturen vergleichen.",
|
||||
"003": "Das Ziel hier ist, die robots.txt-Datei auf Informationslecks des Verzeichnisses oder der Ordnerpfade der Webanwendung zu überprüfen.\n\n 1. Informationsverlust des Verzeichnisses oder der Ordnerpfade der Webanwendung.\n 2. Erstellen Sie die Liste der Verzeichnisse, die von Spiders, Robots oder Crawlern vermieden werden sollen.\n\n Darüber hinaus kann die Liste der Verzeichnisse, die von Spidern, Robots oder Crawlern vermieden werden sollen, auch als Abhängigkeit für Map execution paths durch die Anwendung erstellt werden.\n Webspider, Robots oder Crawler rufen eine Webseite ab und durchlaufen dann rekursiv Hyperlinks, um weitere Webinhalte abzurufen. Ihr akzeptiertes Verhalten wird durch das Robots Exclusion Protocol der robots.txt-Datei im Web-Root-Verzeichnis angegeben.",
|
||||
"004": "Das Ziel besteht darin, die Anwendungen innerhalb des Gültigkeitsbereichs aufzuzählen, die auf einem Webserver vorhanden sind.\n\n Viele Anwendungen haben bekannte Schwachstellen und bekannte Angriffsstrategien, die ausgenutzt werden können, um eine Fernsteuerung zu erlangen oder Daten auszunutzen. Außerdem sind viele Anwendungen oft falsch konfiguriert oder werden nicht aktualisiert.\n Die Erkennung von Webanwendungen ist ein Prozess, der darauf abzielt, Webanwendungen in einer bestimmten Infrastruktur zu identifizieren. Letzteres wird normalerweise als eine Reihe von IP-Adressen (möglicherweise ein Netzblock) angegeben, kann aber auch aus einer Reihe symbolischer DNS-Namen oder einer Mischung aus beiden bestehen.",
|
||||
"005": "Ziel ist es, Webseitenkommentare und Metadaten zu überprüfen, um die Anwendung besser zu verstehen und Informationslecks zu finden.\n\n HTML-Kommentare werden häufig von den Entwicklern verwendet, um Debugging-Informationen über die Anwendung einzufügen. Manchmal vergessen sie die Kommentare.\n\n Überprüfen Sie den HTML-Quellcode auf Kommentare mit vertraulichen Informationen, die dem Angreifer helfen können, mehr Einblick in die Anwendung zu gewinnen. Dies können SQL-Code, Benutzernamen und Passwörter, interne IP-Adressen oder Debugging-Informationen sein.",
|
||||
"006": "Ziel ist es zu verstehen, wie Anfragen gebildet werden und typische Antworten der Anwendung.\n\n Die Aufzählung der Anwendung und ihrer Angriffsfläche ist ein wichtiger Vorläufer bevor gründliche Tests durchgeführt werden können, da es dem Tester ermöglicht, wahrscheinliche Schwachstellen zu identifizieren. Dies soll dazu beitragen, Bereiche innerhalb der Anwendung zu identifizieren und zu kartieren, die untersucht werden sollten, sobald die Aufzählung und Kartierung abgeschlossen sind.\n\n Achten Sie beim Durchlaufen der Anwendung besonders auf alle HTTP-Anforderungen (GET- und POST-Methoden, auch bekannt als Verben) sowie auf alle Parameter und Formularfelder, die an die Anwendung übergeben werden.\n Beachten Sie außerdem alle interessanten Parameter in der URL, den benutzerdefinierten Headern oder dem Text der Anfragen/Antworten und speichern Sie sie.\n Sobald jeder Bereich der Anwendung abgebildet ist, gehen Sie die Anwendung durch und testen Sie jeden der identifizierten Bereiche und machen Sie sich Notizen darüber, was funktioniert hat und was nicht.",
|
||||
"007": "Ziel ist es, die Zielanwendung abzubilden und die wichtigsten Arbeitsabläufe zu verstehen.\n\n Bevor Sie mit Sicherheitstests beginnen, ist es von größter Bedeutung, die Struktur der Anwendung zu verstehen.\nEs gibt mehrere Möglichkeiten, an das Testen und Messen der Codeabdeckung heranzugehen:\n\n 1. Pfad:\n Testen Sie jeden der Pfade durch eine Anwendung, die kombinatorische und Grenzwertanalysetests für jeden Entscheidungspfad umfasst. Während dieser Ansatz Gründlichkeit bietet, wächst die Anzahl der testbaren Pfade exponentiell mit jedem Entscheidungszweig.\n\n 2. Datenfluss (oder Taint-Analyse):\n Testet die Zuweisung von Variablen durch externe Interaktion (normalerweise Benutzer).\n Konzentriert sich auf die Abbildung des Flusses, der Transformation und der Verwendung von Daten in einer Anwendung.\n\n 3. Rennen:\n Testet mehrere gleichzeitige Instanzen der Anwendung, die dieselben Daten manipulieren.",
|
||||
"008": "Ziel ist es, den Typ des verwendeten Web-Frameworks zu definieren, um ein besseres Verständnis der Sicherheitstestmethodik zu erlangen.\n\n Die Art des Frameworks zu kennen, kann automatisch einen großen Vorteil bringen, wenn ein solches Framework bereits vom Penetrationstester getestet wurde. Nicht nur die bekannten Schwachstellen in ungepatchten Versionen, sondern auch spezifische Fehlkonfigurationen im Framework und der bekannten Dateistruktur machen den Fingerprinting-Prozess so wichtig.\n\n Es gibt mehrere gängige Orte, an denen Sie nachsehen können, um den aktuellen Rahmen zu definieren:\n• HTTP-Header\n• Cookies\n• HTML-Quellcode\n• Bestimmte Dateien und Ordner",
|
||||
"009": "Ziel ist es, die Webanwendung und -version zu identifizieren, um bekannte Schwachstellen und die geeigneten Exploits zu ermitteln, die während des Tests verwendet werden können.\n\n Bei der großen Anzahl von Free- und Open-Source-Softwareprojekten, die weltweit aktiv entwickelt und eingesetzt werden, ist es sehr wahrscheinlich, dass ein Anwendungssicherheitstest auf eine Zielseite trifft, die ganz oder teilweise von diesen bekannten Anwendungen abhängig ist (z. B. Wordpress, phpBB, Mediawiki usw.).\n\nDie Kenntnis der zu testenden Webanwendungskomponenten hilft erheblich beim Testprozess.\nDiese wohlbekannten Webanwendungen haben bekannte HTML-Kopfzeilen, Cookies und Verzeichnisstrukturen, die aufgezählt werden können, um die Anwendung zu identifizieren.",
|
||||
"010": "Die Anwendungsarchitektur muss durch einige Tests abgebildet werden, um festzustellen, welche verschiedenen Komponenten zum Erstellen der Webanwendung verwendet werden.\n\n In kleinen Setups, wie z. B. einer einfachen CGI-basierten Anwendung, kann ein einzelner Server verwendet werden, auf dem der Webserver ausgeführt wird, der die C-, Perl- oder Shell-CGIs-Anwendung und möglicherweise auch den Authentifizierungsmechanismus ausführt.\n Bei komplexeren Setups können mehrere Server beteiligt sein. Dazu können ein Reverse-Proxy, ein Frontend-Webserver, ein Anwendungsserver und ein Datenbankserver oder LDAP-Server gehören.\nJeder dieser Server wird für unterschiedliche Zwecke verwendet und kann sogar in verschiedene Netzwerke mit Firewalls dazwischen (DMZs) unterteilt sein.\n\n Darüber hinaus ist das Verständnis der bereitgestellten Konfiguration des Servers, auf dem die Webanwendung gehostet wird, fast so wichtig wie das Testen der Anwendungssicherheit selbst."
|
||||
},
|
||||
"config": {
|
||||
"001": "Die intrinsische Komplexität einer vernetzten und heterogenen Webserver-Infrastruktur, die Hunderte von Webanwendungen umfassen kann, macht das Konfigurationsmanagement und die Überprüfung zu einem grundlegenden Schritt beim Testen und Bereitstellen jeder einzelnen Anwendung. Es braucht nur eine einzige Schwachstelle, um die Sicherheit der gesamten Infrastruktur zu untergraben. Um diese Probleme anzugehen, ist es von größter Bedeutung, eine gründliche Überprüfung der Konfiguration und bekannter Sicherheitsprobleme durchzuführen.\n\nZum Testen der Konfigurationsmanagement-Infrastruktur müssen die folgenden Schritte ausgeführt werden:\n\nSchritt 1:\n Die verschiedenen Elemente, aus denen die Infrastruktur besteht, müssen bestimmt werden, um zu verstehen, wie sie mit einer Webanwendung interagieren und wie sie sich auf deren Sicherheit auswirken.\n\nSchritt 2:\n Alle Elemente der Infrastruktur müssen überprüft werden, um sicherzustellen, dass sie keine bekannten Schwachstellen enthalten.\n\nSchritt 3:\n Es muss eine Überprüfung der Verwaltungsinstrumente durchgeführt werden, die zur Pflege aller verschiedenen Elemente verwendet werden.\n\nSchritt 4:\n Die Authentifizierungssysteme müssen überprüft werden, um sicherzustellen, dass sie die Anforderungen der Anwendung erfüllen und nicht von externen Benutzern manipuliert werden können, um den Zugriff zu nutzen.\n\nSchritt 5:\n Eine Liste definierter Ports, die für die Anwendung erforderlich sind, sollte gepflegt und unter Änderungskontrolle gehalten werden.",
|
||||
"002": "Die Überprüfung und das Testen der Konfiguration ist eine kritische Aufgabe beim Erstellen und Verwalten einer Architektur. Dies liegt daran, dass viele verschiedene Systeme normalerweise mit generischen Konfigurationen bereitgestellt werden, die möglicherweise nicht für die Aufgabe geeignet sind, die sie an dem spezifischen Standort ausführen, an dem sie installiert sind.\n\n Während die typische Web- und Anwendungsserverinstallation viele Funktionen (wie Anwendungsbeispiele, Dokumentation, Testseiten) enthält, sollte das, was nicht unbedingt erforderlich ist, vor der Bereitstellung entfernt werden, um eine Ausnutzung nach der Installation zu vermeiden.\n\nCGI-Scanner enthalten eine detaillierte Liste bekannter Dateien und Verzeichnisbeispiele, die von verschiedenen Web- oder Anwendungsservern bereitgestellt werden.\nAußerdem enthalten Ereignisprotokolle oft Daten, die für einen Angreifer nützlich sind (Information Leakage) oder direkt in Exploits verwendet werden können.",
|
||||
"003": "Dateierweiterungen werden häufig in Webservern verwendet, um einfach zu bestimmen, welche Technologien, Sprachen und Plugins verwendet werden müssen, um die Webanforderung zu erfüllen.\nObwohl dieses Verhalten mit RFCs und Webstandards übereinstimmt, liefert die Verwendung von Standarddateierweiterungen dem Penetrationstester nützliche Informationen über die zugrunde liegenden Technologien, die in einer Web-Appliance verwendet werden.\n\n Die Feststellung, wie Webserver Anfragen verarbeiten, die Dateien mit unterschiedlichen Erweiterungen entsprechen, kann helfen, das Verhalten von Webservern in Abhängigkeit von der Art der Dateien, auf die zugegriffen wird, zu verstehen.\n\nDie folgenden Dateierweiterungen sollten niemals von einem Webserver zurückgegeben werden, da sie sich auf Dateien beziehen, die möglicherweise vertrauliche Informationen enthalten:\n • .asa \n• .inc\n\n Die folgenden Dateierweiterungen beziehen sich auf Dateien, die beim Zugriff entweder angezeigt oder vom Browser heruntergeladen werden.\n Daher müssen Dateien mit diesen Erweiterungen überprüft werden, um sicherzustellen, dass sie tatsächlich geliefert werden sollen:\n• .zip, .tar, .gz, .tgz, .rar, ...: (Komprimierte) Archivdateien\n• .java: Kein Grund, Zugriff auf Java-Quelldateien zu gewähren\n• .txt: Textdateien\n• .pdf: PDF-Dokumente\n• .doc, .rtf, .xls, .ppt, ...: Office-Dokumente\n• .bak, .old und andere Erweiterungen, die auf Sicherungsdateien hinweisen\n\n Um Dateien mit bestimmten Erweiterungen zu identifizieren, kann eine Mischung von Techniken eingesetzt werden.\nDiese Techniken können Vulnerability Scanners, Spidering- und Mirroring-Tools, die manuelle Überprüfung der Anwendung oder Abfragen von Suchmaschinen umfassen.",
|
||||
"004": "Eine wichtige Schwachstellenquelle sind Dateien, die nichts mit der Anwendung zu tun haben, aber als Folge der Bearbeitung von Anwendungsdateien oder nach dem Erstellen von Sicherungskopien im laufenden Betrieb oder durch das Belassen alter Dateien im Webbaum oder ohne Referenz erstellt wurden Dateien.\n\n Theoretisch sollte die Untersuchung von Hand durchgeführt werden, um gründlich zu sein. Da jedoch in den meisten Fällen Kopien von Dateien oder Backup-Dateien unter Verwendung der gleichen Namenskonventionen erstellt werden, kann die Suche einfach per Skript durchgeführt werden.",
|
||||
"005": "Administratorschnittstellen können in der Anwendung oder auf dem Anwendungsserver vorhanden sein, um bestimmten Benutzern zu ermöglichen, privilegierte Aktivitäten auf der Website durchzuführen. Es sollten Tests durchgeführt werden, um festzustellen, ob und wie diese privilegierte Funktionalität von einem nicht autorisierten oder normalen Benutzer abgerufen werden kann.\n\nEine Anwendung erfordert möglicherweise eine Administratorschnittstelle, um einem privilegierten Benutzer den Zugriff auf Funktionen zu ermöglichen, die Änderungen an der Funktionsweise der Site vornehmen können.\nSolche Änderungen können Folgendes umfassen:\n• Bereitstellung von Benutzerkonten\n• Website-Design und -Layout\n• Datenmanipulation\n• Konfigurationsänderungen\n\nIm Folgenden werden Vektoren beschrieben, die zum Testen auf das Vorhandensein von Verwaltungsschnittstellen verwendet werden können:\n• Verzeichnis- und Dateiaufzählung\n• Brute-Forcing-Tools wie THC-HYDRA\n• Kommentare und Links im Quellcode\n• Überprüfung der Server- und Anwendungsdokumentation\n• Öffentlich zugängliche Informationen (z. B. Standardpasswörter)\n• Alternativer Serverport\n• Manipulation von Parametern",
|
||||
"006": "Um diesen Test durchzuführen, muss der Tester irgendwie herausfinden, welche HTTP-Methoden werden vom untersuchten Webserver unterstützt. Die HTTP-Methode OPTIONS bietet dem Tester am meisten direkter und effektiver Weg, dies zu tun. RFC 2616 besagt: „Die OPTIONS-Methode stellt eine Anfrage nach Informationen über die verfügbaren Kommunikationsoptionen in der Anfrage-/Antwortkette dar, die durch den Request-URI identifiziert wird“.\n\n Einige der HTTP-Methoden können potenziell ein Sicherheitsrisiko für eine Webanwendung darstellen, da sie es einem Angreifer ermöglichen, die auf dem Webserver gespeicherten Dateien zu ändern und in einigen Szenarien die Anmeldeinformationen legitimer Benutzer zu stehlen. Genauer gesagt, die Methoden, die deaktiviert werden sollten, sind die folgenden:\n• PUT: Ermöglicht dem Client, Dateien auf den Webserver hochzuladen\n• DELETE: Allwas-Client zum Löschen von Dateien vom Webserver\n• CONNECT: ermöglicht dem Client, den Webserver als Proxy zu verwenden\n• TRACE: Gibt an den Client zurück, was er an den Server gesendet hat",
|
||||
"007": "Die HTTP Strict Transport Security (HSTS)-Funktion ermöglicht es einer Webanwendung, den Browser durch die Verwendung eines speziellen Antwortheaders darüber zu informieren, dass er niemals eine Verbindung zu den angegebenen Domänenservern über HTTP herstellen sollte.\n\n Der strenge HTTP-Transportsicherheitsheader verwendet zwei Anweisungen:\n• max-age\n• includeSubDomain\n\nDas Testen auf das Vorhandensein des HSTS-Headers kann durchgeführt werden, indem das Vorhandensein des HSTS-Headers in der Antwort des Servers in einem Interception-Proxy überprüft wird, oder indem curl verwendet wird.",
|
||||
"008": "Rich Internet Applications (RIA) haben die crossdomain.xml-Richtliniendateien von Adobe übernommen, um einen kontrollierten domänenübergreifenden Zugriff auf Daten und Dienstnutzung mit Technologien wie Oracle Java, Silverlight und Adobe Flash zu ermöglichen. Daher kann eine Domäne den Fernzugriff auf ihre Dienste von einer anderen Domäne aus gewähren.\nOft sind die Richtliniendateien, die die Zugriffsbeschränkungen beschreiben, jedoch schlecht konfiguriert. Eine schlechte Konfiguration der Richtliniendateien ermöglicht Cross-Site Request Forgery-Angriffe.\n\n Um die Schwäche der RIA-Richtliniendatei zu testen, sollte der Tester versuchen, die Richtliniendateien crossdomain.xml und clientaccesspolicy.xml aus dem Stammverzeichnis der Anwendung und aus jedem gefundenen Ordner abzurufen.",
|
||||
"009": "Wenn einer Ressource eine Berechtigungseinstellung zugewiesen wird, die einem größeren Spektrum an Akteuren als erforderlich Zugriff gewährt, kann dies zur Offenlegung vertraulicher Informationen oder zur Änderung dieser Ressource durch unbeabsichtigte Parteien führen. Dies ist besonders gefährlich, wenn die Ressource mit der Programmkonfiguration, der Ausführung oder vertraulichen Benutzerdaten zusammenhängt.\n\nEin klares Beispiel ist eine Ausführungsdatei, die von nicht autorisierten Benutzern ausgeführt werden kann. Ein weiteres Beispiel: Kontoinformationen oder ein Token-Wert für den Zugriff auf eine API – was zunehmend in modernen Webdiensten oder Microservices vorkommt – können in einer Konfigurationsdatei gespeichert werden, deren Berechtigungen bei der Installation standardmäßig auf weltweit lesbar eingestellt sind. Solche sensiblen Daten können durch interne böswillige Akteure des Hosts oder durch einen Remote-Angreifer offengelegt werden, der den Dienst durch andere Schwachstellen kompromittiert, sich aber nur normale Benutzerrechte verschafft hat.\n\nZu den Dateien und Verzeichnissen, die einen Dateiberechtigungstest erfordern, gehören unter anderem:\n• Webdateien/Verzeichnis\n• Konfigurationsdateien/Verzeichnis\n• Sensible Dateien (verschlüsselte Daten, Passwort, Schlüssel)/Verzeichnis\n• Protokolldateien (Sicherheitsprotokolle, Betriebsprotokolle, Administratorprotokolle)/Verzeichnis\n• Ausführbare Dateien (Skripte, EXE, JAR, Klasse, PHP, ASP)/Verzeichnis\n• Datenbankdateien/Verzeichnis\n• Temporäre Dateien/Verzeichnis\n• Dateien/Verzeichnis hochladen",
|
||||
"010": "Eine erfolgreiche Ausnutzung dieser Art von Schwachstelle ermöglicht es einem Gegner, die Subdomain des Opfers zu beanspruchen und die Kontrolle über sie zu übernehmen.\nDieser Angriff beruht auf Folgendem:\n\n1. Der externe DNS-Server-Subdomain-Eintrag des Opfers ist so konfiguriert, dass er auf eine nicht vorhandene oder nicht aktive Ressource/einen externen Dienst/Endpunkt verweist. Die Verbreitung von XaaS-Produkten (Anything as a Service) und öffentlichen Cloud-Diensten bietet viele potenzielle Ziele, die es zu berücksichtigen gilt.\n\n2. Der Dienstanbieter, der die Ressource/den externen Dienst/den Endpunkt hostet, führt die Überprüfung des Subdomain-Eigentums nicht ordnungsgemäß durch.\n\nWenn die Subdomain-Übernahme erfolgreich ist, sind vielfältige Angriffe möglich (Bereitstellung bösartiger Inhalte, Phishing, Diebstahl von Benutzersitzungscookies, Anmeldeinformationen usw.). Diese Schwachstelle könnte für eine Vielzahl von DNS-Ressourceneinträgen ausgenutzt werden, darunter: A, CNAME, MX, NS, TXT usw. In Bezug auf die Angriffsschwere hat eine NS-Subdomänenübernahme (wenn auch weniger wahrscheinlich) die größte Auswirkung, da ein erfolgreicher Angriff dies könnte Dies führt zu vollständiger Kontrolle über die gesamte DNS-Zone und die Domäne des Opfers.\n\nTestziele:\n• Zählen Sie alle möglichen Domänen auf (vorherige und aktuelle).\n• Identifizieren Sie vergessene oder falsch konfigurierte Domänen",
|
||||
"011": "Cloud-Speicherdienste ermöglichen Webanwendungen und -diensten das Speichern und Zugreifen auf Objekte im Speicherdienst. Eine unsachgemäße Konfiguration der Zugriffskontrolle kann jedoch dazu führen, dass vertrauliche Informationen offengelegt werden, Daten manipuliert werden oder unbefugter Zugriff erfolgt.\n\nEin bekanntes Beispiel ist die Fehlkonfiguration eines Amazon S3-Buckets, obwohl auch die anderen Cloud-Speicherdienste ähnlichen Risiken ausgesetzt sein können. Standardmäßig sind alle S3-Buckets privat und können nur von Benutzern aufgerufen werden, denen explizit Zugriff gewährt wurde. Benutzer können öffentlichen Zugriff sowohl auf den Bucket selbst als auch auf einzelne in diesem Bucket gespeicherte Objekte gewähren. Dies kann dazu führen, dass ein unbefugter Benutzer neue Dateien hochladen, gespeicherte Dateien ändern oder lesen kann.\n\nIdentifizieren Sie zunächst die URL für den Zugriff auf die Daten im Speicherdienst und ziehen Sie dann die folgenden Tests in Betracht:\n• Die nicht autorisierten Daten lesen\n• Laden Sie eine neue beliebige Datei hoch\n\nTestziele:\n• Stellen Sie sicher, dass die Zugriffskontrollkonfiguration für die Speicherdienste ordnungsgemäß vorhanden ist"
|
||||
},
|
||||
"ident": {
|
||||
"001": "Das Ziel besteht darin, die in der Anwendung definierten Systemrollen zu validieren, jedes System und jede Geschäftsrolle ausreichend zu definieren und zu trennen, um den angemessenen Zugriff auf Systemfunktionen und -informationen zu verwalten.\n\nAnwendungen verfügen über verschiedene Arten von Funktionalitäten und Diensten und diese erfordern Zugriffsberechtigungen, die auf den Bedürfnissen des Benutzers basieren. Dieser Benutzer könnte sein:\n• ein Administrator, der die Anwendungsfunktionen verwaltet.\n• ein Wirtschaftsprüfer, der die Antragstransaktionen überprüft und einen detaillierten Bericht erstellt.\n• ein Support-Techniker, der Kunden beim Debuggen und Beheben von Problemen in ihren Konten unterstützt.\n• ein Kunde, der mit der Anwendung interagiert und von deren Diensten profitiert.\n\nIn vertrauenswürdigeren Umgebungen, in denen die Vertraulichkeit keine entscheidende Rolle spielt, können sanftere Kontrollen wie Anwendungsworkflow und Audit-Protokollierung die Anforderungen an die Datenintegrität unterstützen, ohne den Benutzerzugriff auf Funktionen einzuschränken. Entwickeln Sie mit oder ohne Hilfe der Systementwickler oder Administratoren eine Rollen-Berechtigungs-Matrix. Die Matrix sollte alle Rollen auflisten, die bereitgestellt werden können, und die zulässigen Berechtigungen untersuchen.\n\nTestziele:\n• Identifizieren und dokumentieren Sie die von der Anwendung verwendeten Rollen.\n• Versuchen Sie, eine andere Rolle zu wechseln, zu ändern oder darauf zuzugreifen.\n• Überprüfen Sie die Granularität der Rollen und die Anforderungen hinter den erteilten Berechtigungen",
|
||||
"002": "Einige Websites bieten einen Benutzerregistrierungsprozess an, der die Bereitstellung des Systemzugriffs für Benutzer automatisiert (oder halbautomatisiert). Die Identitätsanforderungen für den Zugriff variieren von positiver Identifizierung bis zu überhaupt keiner, abhängig von den Sicherheitsanforderungen des Systems.\n\n Schritt 1:\n Stellen Sie sicher, dass die Identitätsanforderungen für die Benutzerregistrierung mit den Geschäfts- und Sicherheitsanforderungen abgestimmt sind.\n\n Schritt 2:\n Bestätigen Sie den Registrierungsprozess.\n\n Stellen Sie sicher, dass die Identitätsanforderungen für die Benutzerregistrierung mit den Geschäfts- und Sicherheitsanforderungen abgestimmt sind:\n• Kann sich jeder für den Zugang registrieren?\n• Werden Registrierungen von einem Menschen überprüft?\n• Kann sich dieselbe Person oder Identität mehrmals registrieren?\n• Können sich Benutzer für verschiedene Rollen oder Berechtigungen registrieren?\n• Welcher Identitätsnachweis ist für eine Anmeldung erforderlich?\n• Werden registrierte Identitäten verifiziert?\n\n Bestätigen Sie den Registrierungsprozess:\n • Können Identitätsinformationen leicht gefälscht oder gefälscht werden?\n • Kann der Austausch von Identitätsinformationen manipuliert werden?",
|
||||
"003": "Überprüfen Sie, welche Konten andere Konten bereitstellen können und welchen Typs.\n\nDie Bereitstellung von Konten bietet einem Angreifer die Möglichkeit, ein gültiges Konto zu erstellen, ohne den ordnungsgemäßen Identifizierungs- und Autorisierungsprozess anzuwenden.\n\nSo testen Sie\n\nBestimmen Sie, welche Rollen Benutzer bereitstellen können und welche Art von Konten sie bereitstellen können:\n• Gibt es eine Überprüfung, Prüfung und Autorisierung von Bereitstellungsanfragen?\n• Gibt es eine Überprüfung, Prüfung und Autorisierung von De-Provisioning-Anfragen?\n• Kann ein Administrator andere Administratoren oder nur Benutzer bereitstellen?\n• Kann ein Administrator oder ein anderer Benutzer Konten mit Berechtigungen versehen, die über ihre eigenen hinausgehen?\n• Kann ein Administrator oder Benutzer die Bereitstellung selbst aufheben?\n• Wie werden die Dateien oder Ressourcen verwaltet, die dem deprovisionierten Benutzer gehören? Werden sie gelöscht? Wird der Zugriff übertragen?",
|
||||
"004": "Der Zweck dieses Tests besteht darin, zu überprüfen, ob es möglich ist, durch Interaktion mit dem Authentifizierungsmechanismus der Anwendung einen Satz gültiger Benutzernamen zu sammeln. Dieser Test ist für Brute-Force-Tests nützlich, bei denen der Tester überprüft, ob es bei einem gültigen Benutzernamen möglich ist, das entsprechende Passwort zu finden.\n\nIn manchen Fällen wird eine Meldung empfangen, die Aufschluss darüber gibt, ob die angegebenen Anmeldeinformationen falsch sind, weil ein ungültiger Benutzername oder ein ungültiges Passwort verwendet wurde. Manchmal können Tester die vorhandenen Benutzer aufzählen, indem sie einen Benutzernamen und ein leeres Passwort senden. Wenn die Anwendung angreifbar ist, erhält der Tester eine Antwortnachricht, die direkt oder indirekt einige Informationen enthält, die für die Enumeration von Benutzern nützlich sind.\n\nTestziele\n• Überprüfen Sie Prozesse, die sich auf die Benutzeridentifizierung beziehen (z. B. Registrierung, Anmeldung usw.).\n• Erfassen Sie Benutzer nach Möglichkeit mithilfe einer Antwortanalyse",
|
||||
"005": "Das Ziel besteht darin, festzustellen, ob eine konsistente Kontonamenstruktur die Anwendung anfällig für die Kontoaufzählung macht. Stellen Sie fest, ob die Fehlermeldungen der Anwendung eine Kontoaufzählung zulassen.\n\nTestziele\n• Stellen Sie fest, ob eine konsistente Kontonamenstruktur die Anwendung anfällig für die Kontoaufzählung macht.\n• Stellen Sie fest, ob die Fehlermeldungen der Anwendung eine Kontoaufzählung zulassen.\n\nBenutzerkontonamen sind häufig stark strukturiert (z. B. lautet der Kontoname von Joe Bloggs jbloggs und der Kontoname von Fred Nurk lautet fnurks), und gültige Kontonamen können leicht erraten werden.\n\nSo testen Sie\n• Bestimmen Sie die Struktur von Kontonamen.\n• Bewerten Sie die Reaktion der Anwendung auf gültige und ungültige Kontonamen.\n• Verwenden Sie unterschiedliche Antworten auf gültige und ungültige Kontonamen, um gültige Kontonamen aufzulisten.\n• Verwenden Sie Kontonamenwörterbücher, um gültige Kontonamen aufzulisten."
|
||||
},
|
||||
"authn": {
|
||||
"001": "Die Analyse konzentriert sich einfach darauf, zu verstehen, ob die Daten unverschlüsselt vom Webbrowser zum Server übertragen werden oder ob die Webanwendung mithilfe eines Protokolls wie HTTPS die geeigneten Sicherheitsmaßnahmen ergreift.\n\n Das Testen auf den Transport von Anmeldeinformationen bedeutet, dass überprüft wird, ob die des Benutzers\nAuthentifizierungsdaten werden über einen verschlüsselten Kanal übertragen, um zu verhindern, dass sie von böswilligen Benutzern abgefangen werden.\n\n Sie können WebScarab oder einen beliebigen Web-Proxy verwenden, um Paket-Header zu erfassen und zu untersuchen.\n Überprüfen Sie, ob HTTPS in jeder sensiblen Anfrage verwendet wird, wie z. B. in Anmeldeseiten, um zu verhindern, dass unbefugte Benutzer die Daten abfangen.",
|
||||
"002": "Häufig sind Anwendungen nach der Installation nicht ordnungsgemäß konfiguriert, und die für die anfängliche Authentifizierung und Konfiguration bereitgestellten Standardanmeldeinformationen werden nie geändert.\n\n Wenn Sie eine Anwendungsschnittstelle identifiziert haben, beispielsweise eine Cisco-Router-Webschnittstelle oder ein Weblogic-Administratorportal, prüfen Sie, ob die bekannten Benutzernamen und Kennwörter für diese Geräte nicht zu einer erfolgreichen Authentifizierung führen. Dazu können Sie die Dokumentation des Herstellers konsultieren oder, viel einfacher, allgemeine Anmeldeinformationen mithilfe einer Suchmaschine oder einer der im Abschnitt „Referenz“ aufgeführten Websites oder Tools finden.\n\n Wenn wir mit Anwendungen konfrontiert werden, für die wir keine Liste mit Standard- und allgemeinen Benutzerkonten haben, können wir versuchen, gültige Standardanmeldeinformationen zu erraten.\n Viele Anwendungen haben ausführliche Fehlermeldungen, die die Site-Benutzer über die Gültigkeit der eingegebenen Benutzernamen informieren. Diese Informationen sind beim Testen auf standardmäßige oder erratbare Benutzerkonten hilfreich.\n\nDa diese Arten von Standardanmeldeinformationen häufig an Administratorkonten gebunden sind, können Sie zunächst die folgenden Benutzernamen ausprobieren: \n• admin \n• administrator \n• root \n• system \n• guest \n• operator \n• super",
|
||||
"003": "Kontosperrmechanismen werden verwendet, um Brute-Force-Angriffe zum Erraten von Passwörtern abzuschwächen. Konten werden in der Regel nach 3 bis 5 erfolglosen Anmeldeversuchen gesperrt und können erst nach einem festgelegten Zeitraum über einen Self-Service-Entsperrmechanismus oder den Eingriff eines Administrators entsperrt werden.\n\n Um die Stärke von Sperrmechanismen zu testen, benötigen Sie in der Regel Zugriff auf ein Konto, das Sie sperren möchten oder sich leisten können:\n\n Schritt 1:\n Bewerten Sie die Fähigkeit des Kontosperrmechanismus, das Erraten von Brute-Force-Passwörtern zu mindern.\n\n Schritt 2:\nBewerten Sie die Widerstandsfähigkeit des Entsperrmechanismus gegen das unbefugte Entsperren von Konten.\n\n Ohne einen starken Sperrmechanismus ist die Anwendung möglicherweise anfällig für Brute-Force-Angriffe. Nach einem erfolgreichen Brute-Force-Angriff könnte ein böswilliger Benutzer Zugriff auf Folgendes haben:\n• Vertrauliche Informationen oder Daten\n• Administratoroberflächen\n• Möglichkeiten für weitere Angriffe",
|
||||
"004": "Während die meisten Anwendungen eine Authentifizierung erfordern, um Zugriff auf private Informationen zu erhalten oder Aufgaben auszuführen, ist nicht jede Authentifizierungsmethode in der Lage, angemessene Sicherheit zu bieten.\n\n Es gibt mehrere Methoden zum Umgehen des Authentifizierungsschemas, das von einer Webanwendung verwendet wird:\n• Direkter Seitenaufruf (Forced Browsing)\n• Parameteränderung\n• Session-ID-Vorhersage\n• SQL-Injektion",
|
||||
"005": "Browser fragen einen Benutzer manchmal, ob er sich das soeben eingegebene Passwort merken möchte.\n\n Das Speichern von Passwörtern im Browser ist nicht nur für Endbenutzer, sondern auch für Angreifer praktisch. Wenn ein Angreifer Zugriff auf den Browser des Opfers erlangen kann (z. B. XSS-Angriff), kann er die gespeicherten Passwörter abrufen.\n Wenn benutzerdefinierte „Remember Me“-Funktionen eingerichtet werden, können außerdem Schwachstellen bei der Speicherung des Tokens auf dem Client-PC die Passwörter der Benutzer offenlegen.\n\n Stellen Sie sicher, dass keine Zugangsdaten im Klartext gespeichert oder in verschlüsselter oder verschlüsselter Form in Cookies leicht abrufbar sind:\n• Suchen Sie nach Passwörtern, die in Cookies gespeichert sind\n• Untersuchen Sie den Hashing-Mechanismus\n• Stellen Sie sicher, dass Anmeldeinformationen nur während der Anmeldung gesendet werden\n• Berücksichtigen Sie sensible Formularfelder",
|
||||
"006": "Browser können Informationen für Caching- und Verlaufszwecke speichern. Caching dient der Leistungssteigerung, sodass zuvor angezeigte Informationen nicht erneut heruntergeladen werden müssen.\n Wenn dem Benutzer sensible Informationen angezeigt werden, können diese Informationen zu Cache- oder Verlaufszwecken gespeichert und daher durch Überprüfen des Cache des Browsers oder durch einfaches Drücken der Schaltfläche „Zurück“ des Browsers abgerufen werden.\n\n Technisch gesehen ist die Schaltfläche „Zurück“ ein Verlauf und kein Cache. Der Cache und der Verlauf sind zwei verschiedene Entitäten. Sie teilen jedoch die gleiche Schwäche, zuvor angezeigte sensible Informationen zu präsentieren.\n\nDie Schaltfläche „Zurück“ kann daran gehindert werden, sensible Daten anzuzeigen.\nDies kann erfolgen durch:\n• Bereitstellung der Seite über HTTPS.\n• Einstellung Cache-Control: must-re-validate",
|
||||
"007": "Der am weitesten verbreitete und am einfachsten zu verwaltende Authentifizierungsmechanismus ist ein statisches Passwort. Es wird bedauert, dass die gängigsten Passwörter immer noch sind: 123456, Passwort und qwerty.\n\nBestimmen Sie den Widerstand der Anwendung gegen Brute-Force-Passworterraten mithilfe verfügbarer Passwortwörterbücher, indem Sie die Anforderungen an Länge, Komplexität, Wiederverwendung und Alterung von Passwörtern bewerten.\n\n Schritt 1:\n Welche Zeichen sind in einem Passwort erlaubt und welche verboten?\nMuss der Benutzer Zeichen aus unterschiedlichen Zeichensätzen wie Klein- und Großbuchstaben, Ziffern und Sonderzeichen verwenden?\n\n Schritt 2:\n Wie oft kann ein Benutzer sein Passwort ändern?\nWie schnell kann ein Benutzer sein Passwort nach einer vorherigen Änderung ändern?\n Benutzer können die Anforderungen des Passwortverlaufs umgehen, indem sie ihr Passwort fünfmal hintereinander ändern.\n\n Schritt 3:\n Wann muss ein Benutzer sein Passwort ändern?\nNach 90 Tagen?\nNach Kontosperrung wegen übermäßiger Anmeldeversuche?\n\n Schritt 4:\n Wie oft kann ein Benutzer ein Passwort wiederverwenden?\n Verwaltet die Anwendung einen Verlauf der zuvor verwendeten 8 Passwörter des Benutzers?\n\n Schritt 5:\n Wie unterschiedlich muss das nächste Passwort vom letzten Passwort sein?\n\n Schritt 6:\nWird der Benutzer daran gehindert, seinen Benutzernamen oder andere Kontoinformationen (z. B. Vor- oder Nachname) im Passwort zu verwenden?",
|
||||
"008": "Oft als „geheime“ Fragen und Antworten bezeichnet, werden Sicherheitsfragen und -antworten oft verwendet, um vergessene Passwörter wiederherzustellen, oder als zusätzliche Sicherheit zusätzlich zum Passwort.\n\n Sie werden normalerweise bei der Kontoerstellung generiert und erfordern, dass der Benutzer aus einigen vorgenerierten Fragen eine Auswahl trifft und eine entsprechende Antwort liefert. Sie können dem Benutzer ermöglichen, seine eigenen Frage-Antwort-Paare zu generieren.\n Beide Methoden sind anfällig für Unsicherheiten. Im Idealfall sollten Sicherheitsfragen Antworten generieren, die nur dem Benutzer bekannt und nicht erratbar oder auffindbar sind.\n\n Der Schlüssel zum erfolgreichen Ausnutzen und Umgehen eines schwachen Sicherheitsfrageschemas besteht darin, eine Frage oder eine Reihe von Fragen zu finden, die die Möglichkeit bieten, die Antworten leicht zu finden. \n\n Schritt 1:\nVersuchen Sie, eine Liste mit Sicherheitsfragen zu erhalten, indem Sie ein neues Konto erstellen oder dem „Ich erinnere mich nicht an mein Passwort“-Prozess folgen.\n\n Schritt 2:\n Versuchen Sie, Sicherheitsfragen zu erstellen, indem Sie ein neues Konto erstellen oder die Kennwortwiederherstellungseigenschaften Ihres vorhandenen Kontos konfigurieren.\nWenn das System dem Benutzer erlaubt, seine eigenen Sicherheitsfragen zu generieren, ist es anfällig dafür, dass unsichere Fragen erstellt werden.\n\n Schritt 3:\n Stellen Sie fest, ob eine Reihe falsch eingegebener Sicherheitsantworten einen Sperrmechanismus auslösen.",
|
||||
"009": "Die Funktion zum Ändern und Zurücksetzen von Kennwörtern einer Anwendung ist ein Self-Service-Mechanismus zum Ändern oder Zurücksetzen von Kennwörtern für Benutzer.\n Dieser Self-Service-Mechanismus ermöglicht es Benutzern, ihr Passwort schnell zu ändern oder zurückzusetzen, ohne dass ein Administrator eingreifen muss.\n\n Schritt 1:\n Bestimmen Sie den Widerstand der Anwendung gegen die Subversion des Kontoänderungsprozesses, der es jemandem ermöglicht, das Kennwort eines Kontos zu ändern.\n\n Schritt 2:\nBestimmen Sie die Widerstandsfähigkeit der Funktion zum Zurücksetzen von Passwörtern gegen Erraten oder Umgehen.\n\n Sowohl für die Passwortänderung als auch für das Zurücksetzen des Passworts ist es wichtig, dies zu überprüfen.\n\n.. wenn andere Benutzer als Administratoren Kennwörter für andere Konten als ihre eigenen ändern oder zurücksetzen können.\n.. wenn Benutzer den Prozess zum Ändern oder Zurücksetzen von Passwörtern manipulieren oder untergraben können.\n.. wenn der Prozess zum Ändern oder Zurücksetzen des Passworts anfällig für CSRF ist.",
|
||||
"010": "Auch wenn die primären Authentifizierungsmechanismen keine Schwachstellen enthalten, kann es sein, dass Schwachstellen in alternativen legitimen Benutzerkanälen für die Authentifizierung für dieselben Benutzerkonten vorhanden sind.\n\n Es sollten Tests durchgeführt werden, um alternative Kanäle zu identifizieren und, vorbehaltlich des Testumfangs, Schwachstellen zu identifizieren.\n Einige dieser Kanäle können selbst separate Webanwendungen sein, die unterschiedliche Hostnamen oder Pfade verwenden. Zum Beispiel:\n• Standard-Website\n• Mobile Website\n• Zugänglichkeitsoptimierte Website\n• Parallele Websites, die dieselben Benutzerkonten verwenden\n• Entwicklung, UAT und Versionen der Standard-Website\n\n Es könnten aber auch andere Arten von Anwendungen oder Geschäftsprozessen sein:\n• App für mobile Geräte\n• Desktopanwendung\n• Call-Center-Betreiber\n• Interaktive Sprachantwort oder Telefonbaumsysteme"
|
||||
},
|
||||
"authz": {
|
||||
"001": "Viele Webanwendungen verwenden und verwalten Dateien im Rahmen ihres täglichen Betriebs. Durch die Verwendung von Eingabevalidierungsmethoden, die nicht gut entwickelt oder eingesetzt wurden, könnte ein Angreifer das System ausnutzen, um Dateien zu lesen oder zu schreiben, auf die nicht zugegriffen werden soll. In bestimmten Situationen kann es möglich sein, beliebigen Code oder Systembefehle auszuführen.\n\n Bei Webservern und Webanwendungen tritt diese Art von Problem bei Path Traversal/File Include-Angriffen auf. Während einer Bewertung müssen Tester zwei verschiedene Phasen durchführen, um Path Traversal und File Include-Fehler zu entdecken:\n\n Stufe 1:\n Input Vectors Enumeration (eine systematische Auswertung jedes Input-Vektors)\n\n Stufe 2:\n Testtechniken (eine methodische Bewertung jeder Angriffstechnik, die von einem Angreifer verwendet wird, um die Schwachstelle auszunutzen)\n\n Die nächste Testphase besteht in der Analyse der in der Webanwendung vorhandenen Eingabevalidierungsfunktionen. Unter Verwendung des vorherigen Beispiels lädt die dynamische Seite namens getUserProfile.jsp statische Informationen aus einer Datei und zeigt Benutzern den Inhalt an. Ein Angreifer könnte die böswillige Zeichenfolge „../../../../etc/passwd“ einfügen, um die Passwort-Hash-Datei einzufügen.\n Es ist ein häufiger Fehler von Entwicklern, nicht jede Form der Codierung zu erwarten und daher nur grundlegende codierte Inhalte zu validieren. Wenn die Testzeichenfolge zunächst nicht erfolgreich ist, versuchen Sie es mit einem anderen Codierungsschema.",
|
||||
"002": "Diese Art von Test konzentriert sich darauf, zu überprüfen, wie das Autorisierungsschema für jede Rolle oder jedes Privileg implementiert wurde, um Zugriff auf reservierte Funktionen und Ressourcen zu erhalten.\n\nFür jede spezifische Rolle, die der Tester während der Bewertung innehat, für jede Funktion und Anforderung, die die Anwendung während der Phase nach der Authentifizierung ausführt, muss Folgendes überprüft werden:\n • Ist es möglich, auf diese Ressource zuzugreifen, selbst wenn der Benutzer nicht authentifiziert ist?\n • Kann nach dem Abmelden auf diese Ressource zugegriffen werden?\n • Ist es möglich, auf Funktionen und Ressourcen zuzugreifen, die einem Benutzer mit einer anderen Rolle oder Berechtigung zugänglich sein sollten?\n\n Versuchen Sie, als Administrator auf die Anwendung zuzugreifen, und verfolgen Sie alle Verwaltungsfunktionen:\n • Ist der Zugriff auf Verwaltungsfunktionen auch dann möglich, wenn der Tester als Benutzer mit Standardrechten angemeldet ist?\n• Ist es möglich, diese Verwaltungsfunktionen als Benutzer mit einer anderen Rolle zu verwenden, und wem sollte diese Aktion verweigert werden?",
|
||||
"003": "Eine Rechteausweitung tritt auf, wenn ein Benutzer Zugriff auf mehr Ressourcen oder Funktionen erhält, als ihm normalerweise gestattet sind.\n\n Während dieser Phase sollte der Tester sicherstellen, dass es einem Benutzer nicht möglich ist, seine Berechtigungen oder Rollen innerhalb der Anwendung auf eine Weise zu ändern, die Angriffe zur Rechteausweitung ermöglichen könnte.\n Der Grad der Eskalation hängt davon ab, welche Privilegien der Angreifer besitzen darf und welche Privilegien bei einem erfolgreichen Exploit erworben werden können.\n\n In jedem Teil der Anwendung, in dem ein Benutzer Informationen in der Datenbank erstellen (z. B. eine Zahlung vornehmen oder eine Nachricht senden), Informationen empfangen (Kontoauszug, Bestelldetails usw.) oder Informationen löschen (Benutzer löschen, Nachrichten usw.), ist es notwendig, diese Funktionalität aufzuzeichnen.\n Versuchen Sie, als anderer Benutzer auf solche Funktionen zuzugreifen, um zu überprüfen, ob es möglich ist, auf eine Funktion zuzugreifen, die aufgrund der Rolle/Berechtigung des Benutzers nicht zulässig sein sollte.",
|
||||
"004": "Unsichere direkte Objektverweise treten auf, wenn eine Anwendung basierend auf Benutzereingaben direkten Zugriff auf Objekte bereitstellt.\n Durch diese Schwachstelle können Angreifer die Autorisierung umgehen und direkt auf Ressourcen im System zugreifen, beispielsweise Datenbankeinträge oder Dateien.\n\n Unsichere direkte Objektreferenzen ermöglichen es Angreifern, die Autorisierung zu umgehen und direkt auf Ressourcen zuzugreifen, indem sie den Wert eines Parameters ändern, der verwendet wird, um direkt auf ein Objekt zu verweisen.\n\n Um diese Schwachstelle zu testen, muss der Tester zunächst alle Stellen in der Anwendung abbilden, an denen Benutzereingaben verwendet werden, um direkt auf Objekte zu verweisen.\n Der beste Weg, um auf direkte Objektreferenzen zu testen, wäre, mindestens zwei (häufig mehr) Benutzer zu haben, um verschiedene Objekte und Funktionen im Besitz abzudecken.\n Indem er mehrere Benutzer hat, spart der Tester wertvolle Testzeit beim Erraten unterschiedlicher Objektnamen, da er versuchen kann, auf Objekte zuzugreifen, die dem anderen Benutzer gehören."
|
||||
},
|
||||
"sess": {
|
||||
"001": "Um eine kontinuierliche Authentifizierung für jede Seite einer Website oder eines Dienstes zu vermeiden, implementieren Webanwendungen verschiedene Mechanismen, um Anmeldeinformationen für einen festgelegten Zeitraum zu speichern und zu validieren.\n Diese Mechanismen werden als Sitzungsverwaltung bezeichnet.\n\n In diesem Test möchte der Tester überprüfen, ob Cookies und andere Sitzungstoken auf sichere und unvorhersehbare Weise erstellt werden. Ein Angreifer, der in der Lage ist, ein schwaches Cookie vorherzusagen und zu fälschen, kann leicht die Sitzungen legitimer Benutzer kapern.\n Aufgrund der Bedeutung der von ihnen gespeicherten Daten sind Cookies daher für die Gesamtsicherheit der Anwendung von entscheidender Bedeutung. Bei diesem Test muss der Tester überprüfen, ob die an Clients ausgegebenen Cookies einer Vielzahl von Angriffen widerstehen können, die darauf abzielen, die Sitzungen legitimer Benutzer und die Anwendung selbst zu stören.\n\n Normalerweise sind die Hauptschritte des Angriffsmusters die folgenden:\n• Cookie-Sammlung\n• Cookie-Reverse-Engineering\n• Cookie-Manipulation\n\n Ein weiteres Angriffsmuster besteht darin, einen Cookie zum Überlaufen zu bringen. Genau genommen hat dieser Angriff einen anderen Charakter, da Tester hier nicht versuchen, ein vollkommen gültiges Cookie nachzubilden. Stattdessen besteht das Ziel darin, einen Speicherbereich zum Überlaufen zu bringen und dadurch das korrekte Verhalten der Anwendung zu stören.",
|
||||
"002": "Cookies sind oft ein wichtiger Angriffsvektor für böswillige Benutzer, und die Anwendung sollte immer die gebotene Sorgfalt walten lassen, um Cookies zu schützen. In diesem Abschnitt wird erläutert, wie eine Anwendung beim Zuweisen von Cookies die erforderlichen Vorkehrungen treffen und testen kann, ob diese Attribute korrekt konfiguriert wurden.\n\n Aufgrund der sensiblen Natur von Informationen in Cookies werden diese typischerweise kodiert oder verschlüsselt, um die darin enthaltenen Informationen zu schützen.\n Sobald der Tester verstanden hat, wie Cookies gesetzt werden, wann sie gesetzt werden, wofür sie verwendet werden, warum sie verwendet werden und welche Bedeutung sie haben, sollten sie sich ansehen, welche Attribute für ein Cookie gesetzt werden können und wie sie getestet werden wenn sie sicher sind.\n\nDurch die Verwendung eines abfangenden Proxys oder eines Browser-Plug-ins zum Abfangen von Datenverkehr fangen Sie alle Antworten ab, bei denen ein Cookie von der Anwendung gesetzt wird (unter Verwendung der Set-cookie-Anweisung), und untersuchen Sie das Cookie auf Folgendes:\n• Secure-Attribut\n• HttpOnly-Attribut\n• Domain-Attribut\n• Path-Attribut\n• Expires-Attribut",
|
||||
"003": "Wenn eine Anwendung ihre Sitzungscookies nach einer erfolgreichen Benutzerauthentifizierung nicht erneuert, könnte es möglich sein, eine Schwachstelle bei der Sitzungsfixierung zu finden und einen Benutzer zu zwingen, ein dem Angreifer bekanntes Cookie zu verwenden. In diesem Fall könnte ein Angreifer die Benutzersitzung stehlen (Session-Hijacking).\n\n Sicherheitslücken bei der Sitzungsfixierung treten auf, wenn..\n ... eine Webanwendung einen Benutzer authentifiziert, ohne zuerst die vorhandene Sitzungs-ID ungültig zu machen, wodurch die bereits mit dem Benutzer verknüpfte Sitzungs-ID weiterhin verwendet wird\n.. ein Angreifer in der Lage ist, einem Benutzer eine bekannte Sitzungs-ID aufzuzwingen, sodass der Angreifer nach der Authentifizierung des Benutzers Zugriff auf die authentifizierte Sitzung hat.\n\n Beim generischen Exploit von Sicherheitslücken zur Sitzungsfixierung erstellt ein Angreifer eine neue Sitzung in einer Webanwendung und zeichnet die zugehörige Sitzungskennung auf. Der Angreifer veranlasst dann das Opfer, sich mit derselben Sitzungskennung beim Server zu authentifizieren, wodurch der Angreifer während der aktiven Sitzung Zugriff auf das Konto des Benutzers erhält.",
|
||||
"004": "Die Sitzungstoken (Cookie, Sitzungs-ID, verborgenes Feld) ermöglichen es einem Angreifer normalerweise, sich als Opfer auszugeben und unrechtmäßig auf die Anwendung zuzugreifen, wenn sie offengelegt werden. Es ist wichtig, dass sie jederzeit vor Abhören geschützt sind, insbesondere während der Übertragung zwischen dem Client-Browser und den Anwendungsservern.\n\n Über einen persönlichen Proxy kann zu jeder Anfrage und Antwort Folgendes festgestellt werden:\n • Verwendetes Protokoll (z. B. HTTP vs. HTTPS)\n • HTTP-Header\n • Nachrichtentext (z. B. POST oder Seiteninhalt)\n\n Schutz vor Lauschangriffen wird oft durch SSL-Verschlüsselung bereitgestellt, kann aber auch andere Tunnel oder Verschlüsselung beinhalten. Wenn die Sitzungs-ID von einem Angreifer der Anwendung präsentiert werden könnte, um sich Zugriff zu verschaffen, muss sie während der Übertragung geschützt werden, um dieses Risiko zu mindern. Daher sollte sichergestellt werden, dass die Verschlüsselung für alle Anfragen oder Antworten, bei denen die Sitzungs-ID übergeben wird, sowohl standardmäßig als auch durchgesetzt wird, unabhängig vom verwendeten Mechanismus.\n\n Jedes Mal, wenn die Authentifizierung erfolgreich ist, sollte der Benutzer Folgendes erwarten:\n• Ein anderes Sitzungstoken\n• Ein Token, das für jede HTTP-Anforderung über einen verschlüsselten Kanal gesendet wird",
|
||||
"005": "CSRF ist ein Angriff, der einen Endbenutzer dazu zwingt, unerwünschte Aktionen auf einer Webanwendung auszuführen, in der er/sie gerade authentifiziert ist.\nEin erfolgreicher CSRF-Exploit kann die Daten und den Betrieb von Endbenutzern gefährden, wenn er auf einen normalen Benutzer abzielt. Wenn der Zielbenutzer das Administratorkonto ist, kann ein CSRF-Angriff die gesamte Webanwendung gefährden.\n CSRF stützt sich auf Folgendes:\n\n Punkt 1:\n Verhalten des Webbrowsers in Bezug auf den Umgang mit sitzungsbezogenen Informationen wie Cookies und HTTP-Authentifizierungsinformationen;\n\n Punkt 2:\n Kenntnis des Angreifers von gültigen Webanwendungs-URLs;\n\n Punkt 3:\n Anwendungssitzungsverwaltung, die sich nur auf Informationen stützt, die dem Browser bekannt sind;\n\n Punkt 4:\n Vorhandensein von HTML-Tags, deren Vorhandensein einen sofortigen Zugriff auf eine http[s]-Ressource bewirkt; zum Beispiel das Image-Tag img\n\n Der Tester muss URLs im eingeschränkten (authentifizierten) Bereich kennen. Wenn sie über gültige Anmeldeinformationen verfügen, können sie beide Rollen einnehmen – Angreifer und Opfer. In diesem Fall kennen Tester die zu testenden URLs, indem sie sich einfach umsehen.\n\n Wenn sich die Sitzungsverwaltung nur auf clientseitige Werte stützt (Informationen, die dem Browser zur Verfügung stehen), ist die Anwendung anfällig.\n Damit eine Anwendung nicht anfällig ist, muss sie sitzungsbezogene Informationen in der URL enthalten, und zwar in einer Form, die für den Benutzer nicht identifizierbar oder unvorhersehbar ist.",
|
||||
"006": "Die Sitzungsbeendigung ist ein wichtiger Teil des Sitzungslebenszyklus. Das Verkürzen der Lebensdauer der Sitzungstoken auf ein Minimum verringert die Wahrscheinlichkeit eines erfolgreichen Sitzungs-Hijacking-Angriffs. Dies kann als Kontrolle gegen andere Angriffe wie Cross Site Scripting und Cross Site Request Forgery angesehen werden. Es ist bekannt, dass solche Angriffe darauf beruhen, dass ein Benutzer eine authentifizierte Sitzung hat.\n\n Eine sichere Sitzungsbeendigung erfordert mindestens die folgenden Komponenten:\n • Verfügbarkeit von Steuerelementen der Benutzeroberfläche, mit denen sich der Benutzer manuell abmelden kann\n • Sitzungsbeendigung nach einer bestimmten Zeit ohne Aktivität (Session-Timeout)\n • Ordnungsgemäße Invalidierung des serverseitigen Sitzungsstatus\n\n Der richtige Wert für das Sitzungs-Timeout hängt vom Zweck der Anwendung ab und sollte ein Gleichgewicht zwischen Sicherheit und Benutzerfreundlichkeit darstellen.",
|
||||
"007": "In dieser Phase überprüfen Tester, ob die Anwendung einen Benutzer automatisch abmeldet, wenn dieser Benutzer eine bestimmte Zeit lang inaktiv war, um sicherzustellen, dass dieselbe Sitzung nicht „wiederverwendet“ werden kann und dass keine sensiblen Daten im Browser-Cache gespeichert bleiben .\n\n Das Leerlaufzeitlimit schränkt die Wahrscheinlichkeit ein, dass ein Angreifer eine gültige Sitzungs-ID eines anderen Benutzers erraten und verwenden muss, und könnte unter bestimmten Umständen öffentliche Computer vor der Wiederverwendung von Sitzungen schützen. Verwaltung und Ablauf von Sitzungszeitüberschreitungen müssen serverseitig erzwungen werden. Wenn einige Daten unter der Kontrolle des Clients verwendet werden, um das Sitzungs-Timeout zu erzwingen, könnte ein Angreifer diese manipulieren, um die Sitzungsdauer zu verlängern.\n\n Schritt 1:\nTester müssen prüfen, ob ein Timeout vorliegt, indem sie sich beispielsweise anmelden und auf das Auslösen des Timeout-Logouts warten. Wie bei der Abmeldefunktion sollten nach Ablauf des Timeouts alle Sitzungstoken zerstört oder unbrauchbar sein.\n\n Schritt 2:\n Wenn das Timeout konfiguriert ist, müssen Tester verstehen, ob das Timeout vom Client oder vom Server erzwungen wird.\n\n Generell sollte serverseitig alles überprüft werden und es sollte nicht möglich sein, durch Zurücksetzen der Session-Cookies auf vorherige Werte wieder auf die Anwendung zuzugreifen.",
|
||||
"008": "Das Überladen von Sitzungsvariablen (Session Puzzling) ist eine Schwachstelle auf Anwendungsebene, die es einem Angreifer ermöglichen kann, eine Vielzahl von böswilligen Aktionen auszuführen, einschließlich, aber nicht beschränkt auf ...\n.. effiziente Mechanismen zur Durchsetzung der Authentifizierung umgehen und sich als legitime Benutzer ausgeben.\n.. erhöhen der Rechte eines böswilligen Benutzerkontos in einer Umgebung, die ansonsten als narrensicher gelten würde.\n.. Qualifizierungsphasen in mehrphasigen Prozessen überspringen, selbst wenn der Prozess Einschränkungen auf Codeebene enthält.\n.. serverseitige Werte mit indirekten Methoden manipulieren, die nicht vorhergesagt oder erkannt werden können.\n.. herkömmliche Angriffe an Orten ausführen, die zuvor unerreichbar waren oder sogar als sicher galten.\n\n Diese Schwachstelle tritt auf, wenn eine Anwendung dieselbe Sitzungsvariable für mehr als einen Zweck verwendet. Es kann erkannt und ausgenutzt werden, indem alle Sitzungsvariablen, die von der Anwendung verwendet werden, und in welchem \u200B\u200BKontext sie gültig sind, aufgelistet werden. Dies ist insbesondere möglich, indem auf eine Folge von Einstiegspunkten zugegriffen und dann Ausstiegspunkte untersucht werden.",
|
||||
"009": "Ein Angreifer, der Zugriff auf Benutzersitzungscookies erhält, kann sich durch die Bereitstellung solcher Cookies als diese ausgeben. Dieser Angriff wird als Session-Hijacking bezeichnet. Betrachtet man Netzwerkangreifer, d. h. Angreifer, die das vom Opfer verwendete Netzwerk kontrollieren, können Sitzungscookies dem Angreifer über HTTP unangemessen zugänglich gemacht werden. Um dies zu verhindern, sollten Sitzungscookies mit dem Attribut „Sicher“ gekennzeichnet werden, sodass sie nur über HTTPS kommuniziert werden.\n\nTestziele\n• Identifizieren Sie anfällige Sitzungscookies.\n• Kapern Sie anfällige Cookies und bewerten Sie das Risikoniveau.\n\nSo testen Sie\nHier sind die Schritte zur Durchführung dieses Tests:\n1. Melden Sie sich als Opfer auf der Website an und gelangen Sie zu einer beliebigen Seite, die eine sichere Funktion bietet, die eine Authentifizierung erfordert.\n2. Löschen Sie alle Cookies aus der Keksdose, die eine der folgenden Bedingungen erfüllen.\n• Falls keine HSTS-Übernahme erfolgt: Das Secure-Attribut ist gesetzt.\n• bei teilweiser HSTS-Einführung: Das Secure-Attribut ist gesetzt oder das Domain-Attribut ist nicht gesetzt.\n3. Speichern Sie einen Schnappschuss der Keksdose.\n4. Lösen Sie die in Schritt 1 identifizierte sichere Funktion aus.\n5. Beobachten Sie, ob der Vorgang in Schritt 4 erfolgreich durchgeführt wurde. Wenn ja, war der Angriff erfolgreich.\n6. Leeren Sie die Keksdose, melden Sie sich als Angreifer an und gelangen Sie zur Seite bei Schritt 1.\n7. Schreiben Sie die in Schritt 3 gespeicherten Kekse nacheinander in die Keksdose.\n8. Lösen Sie die in Schritt 1 identifizierte Sicherheitsfunktion erneut aus.\n9. Leeren Sie die Keksdose und melden Sie sich erneut als Opfer an.\n10. Beobachten Sie, ob der Vorgang in Schritt 8 im Konto des Opfers erfolgreich durchgeführt wurde. Wenn ja, war der Angriff erfolgreich; andernfalls ist die Site vor Session-Hijacking geschützt.\n\nBeachten Sie, dass das Secure-Attribut auch verwendet werden sollte, wenn die Webanwendung vollständig über HTTPS bereitgestellt wird, da sonst der folgende Cookie-Diebstahl-Angriff möglich ist. Gehen Sie davon aus, dass example.com vollständig über HTTPS bereitgestellt wird, seine Sitzungscookies jedoch nicht als „sicher“ markiert.\n\nFolgende Angriffsschritte sind möglich:\n1. Das Opfer sendet eine Anfrage an http://another-site.com.\n2. Der Angreifer manipuliert die entsprechende Antwort, sodass eine Anfrage an http://example.com ausgelöst wird.\n3. Der Browser versucht nun, auf http://example.com zuzugreifen.\n4. Obwohl die Anfrage fehlschlägt, werden die Sitzungscookies im Klartext über HTTP weitergegeben.\n\nWenn das Domänenattribut festgelegt ist, können Sitzungscookies über Subdomänen hinweg gemeinsam genutzt werden. Die Verwendung von HTTP mit Subdomains sollte vermieden werden, um die Offenlegung unverschlüsselter, über HTTP gesendeter Cookies zu verhindern. Um diese Sicherheitslücke zu veranschaulichen, gehen wir davon aus, dass die Website example.com HSTS ohne die Option includeSubDomains aktiviert. Die Website gibt Sitzungscookies aus, wobei das Domain-Attribut auf example.com festgelegt ist.\n\nFolgender Angriff ist möglich:\n1. Das Opfer sendet eine Anfrage an http://another-site.com.\n2. Der Angreifer manipuliert die entsprechende Antwort, sodass eine Anfrage an http://fake.example.com ausgelöst wird.\n3. Der Browser versucht nun, auf http://fake.example.com zuzugreifen, was die HSTS-Konfiguration zulässt.\n4. Da die Anfrage an eine Unterdomäne von example.com mit festgelegtem Domänenattribut gesendet wird, enthält sie die Sitzungscookies, die im Klartext über HTTP durchgesickert sind."
|
||||
},
|
||||
"inpval": {
|
||||
"001": "Reflected Cross-Site Scripting (XSS) tritt auf, wenn ein Angreifer ausführbaren Browsercode in eine einzelne HTTP-Antwort einfügt.\nDer eingeschleuste Angriff wird nicht in der Anwendung selbst gespeichert; Es ist nicht dauerhaft und wirkt sich nur auf Benutzer aus, die einen in böser Absicht erstellten Link oder eine Webseite eines Drittanbieters öffnen.\nDie Angriffszeichenfolge ist Teil der präparierten URI- oder HTTP-Parameter, wird von der Anwendung nicht ordnungsgemäß verarbeitet und an das Opfer zurückgegeben. Eine der Hauptschwierigkeiten beim Verhindern von XSS-Schwachstellen ist die richtige Zeichencodierung.\n In einigen Fällen filtert der Webserver oder die Webanwendung möglicherweise einige Zeichencodierungen nicht, sodass die Webanwendung beispielsweise „<script>“ herausfiltert, aber nicht %3cscript%3e filtert, das einfach eine andere Codierung enthält von Tags. Ein Test umfasst mindestens drei Phasen:\n\n Phase 1:\nEingabevektoren erkennen. Für jede Webseite muss der Tester alle benutzerdefinierten Variablen der Webanwendung und deren Eingabe bestimmen. Dazu gehören versteckte oder nicht offensichtliche Eingaben wie HTTP-Parameter, POST-Daten, versteckte Formularfeldwerte und vordefinierte Radio- oder Auswahlwerte. In der Regel werden HTML-Editoren im Browser oder Web-Proxys verwendet, um diese versteckten Variablen anzuzeigen.\n\n Phase 2:\n Analysieren Sie jeden Eingabevektor, um potenzielle Schwachstellen zu erkennen. dUm eine XSS-Schwachstelle zu erkennen, verwendet der Tester normalerweise speziell gestaltete Eingabedaten mit jedem Eingabevektor. Solche Eingabedaten sind in der Regel harmlos, lösen jedoch Reaktionen des Webbrowsers aus, der die Schwachstelle manifestiert. Testdaten können mithilfe eines Webanwendungs-Fuzzers, einer automatisierten vordefinierten Liste bekannter Angriffszeichenfolgen oder manuell generiert werden.\n\n Phase 3:\n Für jede Testeingabe, die in der vorherigen Phase versucht wurde, analysiert der Tester das Ergebnis und bestimmt, ob es sich um eine Schwachstelle handelt, die realistische Auswirkungen auf die Sicherheit der Webanwendung hat. Dazu muss der HTML-Code der resultierenden Webseite untersucht und nach der Testeingabe gesucht werden. Einmal gefunden, identifiziert der Tester alle Sonderzeichen, die nicht richtig codiert, ersetzt oder herausgefiltert wurden.",
|
||||
"002": "Stored Cross Site Scripting (XSS) ist die gefährlichste Art von Cross Site Scripting.\n\n Gespeichertes XSS tritt auf, wenn eine Webanwendung Eingaben von einem Benutzer sammelt, die möglicherweise böswillig sind, und diese Eingaben dann zur späteren Verwendung in einem Datenspeicher speichert. Die gespeicherte Eingabe wird nicht korrekt gefiltert. Infolgedessen scheinen die schädlichen Daten Teil der Website zu sein und werden im Browser des Benutzers unter den Rechten der Webanwendung ausgeführt.\n\n Eine erfolgreiche Ausnutzung liegt vor, wenn ein Benutzer eine Seite mit einem gespeicherten XSS besucht.\nDie folgenden Phasen beziehen sich auf ein typisches Szenario eines gespeicherten XSS-Angriffs:\n • Der Angreifer speichert schädlichen Code auf der anfälligen Seite\n • Der Benutzer authentifiziert sich in der Anwendung\n • Benutzer besucht anfällige Seite\n • Schädlicher Code wird vom Browser des Benutzers ausgeführt\n\n Diese Schwachstelle kann verwendet werden, um eine Reihe von browserbasierten Angriffen durchzuführen, darunter:\n • Hijacking des Browsers eines anderen Benutzers\n • Erfassen vertraulicher Informationen, die von Benutzern angezeigt werden\n • Pseudo-Verunstaltung der Anwendung\n • Port-Scanning interner Hosts\n • Gezielte Bereitstellung browserbasierter Exploits\n • Andere böswillige Aktivitäten",
|
||||
"003": "Die HTTP-Spezifikation enthält andere Anforderungsmethoden als die standardmäßigen GET- und POST-Anforderungen. Ein standardkonformer Webserver kann auf diese alternativen Methoden auf eine Weise reagieren, die von Entwicklern nicht erwartet wurde.\n\n Da der HTML-Standard keine anderen Anfragemethoden als GET oder POST unterstützt, müssen wir benutzerdefinierte HTTP-Anfragen erstellen, um die anderen Methoden zu testen.\n\n Die vollständige HTTP 1.1-Spezifikation definiert die folgenden gültigen HTTP-Anforderungsmethoden oder Verben: \n • OPTIONS \n • GET \n • HEAD \n • POST \n • PUT \n • DELETE \n • TRACE \n • CONNECT \n\n Wenn diese Option aktiviert ist, lassen die Erweiterungen Web Distributed Authoring and Version (WebDAV) mehrere weitere HTTP-Methoden zu: \n • PROPFIND \n • PROPPATCH \n • MKCOL \n • COPY \n • MOVE \n • LOCK \n • UNLOCK",
|
||||
"004": "Das Bereitstellen mehrerer HTTP-Parameter mit demselben Namen kann dazu führen, dass eine Anwendung Werte auf unerwartete Weise interpretiert. Durch Ausnutzen dieser Effekte kann ein Angreifer möglicherweise die Eingabevalidierung umgehen, Anwendungsfehler auslösen oder interne Variablenwerte ändern. Da HTTP Parameter Pollution (kurz HPP) einen Baustein aller Webtechnologien betrifft, existieren server- und clientseitige Angriffe.\n\n Da die Zuweisung von HTTP-Parametern in der Regel über den Webanwendungsserver und nicht über den Anwendungscode selbst erfolgt, sollte das Testen der Reaktion auf Parameterverschmutzung zum Glück Standard für alle Seiten und Aktionen sein.\n Da jedoch fundierte Kenntnisse der Geschäftslogik erforderlich sind, erfordert das Testen von HPP manuelles Testen.\n Automatische Tools können Prüfer nur teilweise unterstützen, da sie dazu neigen, zu viele Fehlalarme zu generieren. Darüber hinaus kann sich HPP in clientseitigen und serverseitigen Komponenten manifestieren.",
|
||||
"005": "SQL-Injection-Angriffe sind eine Art von Injection-Angriffen, bei denen SQL-Befehle in Eingaben auf Datenebene eingeschleust werden, um die Ausführung vordefinierter SQL-Befehle zu beeinflussen.\n\n Der Tester kann präparierte Eingaben liefern, die versuchen, die ursprüngliche SQL-Anweisung dazu zu bringen, weitere Aktionen nach Wahl des Testers auszuführen. \n Beispielsweise könnte der Tester eine Anweisung in „$password = 1“ oder „1“ = „1“ ändern, die Logik der SQL-Anweisung ändern und die WHERE-Klausel ändern, indem er eine Bedingung hinzufügt „oder „1“ = „1“.\n\n SQL-Injection-Angriffe können in die folgenden drei Klassen eingeteilt werden: \n • Inband \n • Out-of-band \n • Inferential or Blind \n\n Bei den Techniken zum Ausnutzen von SQL-Injection-Fehlern gibt es fünf gängige Techniken. Diese Techniken können manchmal auch kombiniert verwendet werden:\n • Union Operator \n • Boolean \n • Error based \n • Out-of-band \n • Time delay",
|
||||
"005_1": "Webbasierte PL/SQL-Anwendungen werden durch das PL/SQL-Gateway ermöglicht, das die Komponente ist, die Webanforderungen in Datenbankabfragen übersetzt. Oracle hat eine Reihe von Softwareimplementierungen entwickelt.\n Zu den Produkten, die das PL/SQL-Gateway verwenden, gehören unter anderem Oracle HTTP Server, eBusiness Suite, Portal, HTMLDB, WebDB und Oracle Application Server.\n\n Im Wesentlichen fungiert das PL/SQL-Gateway einfach als Proxy-Server, der die Webanfrage des Benutzers entgegennimmt und an den Datenbankserver weiterleitet, wo sie ausgeführt wird.\n\n Schritt 1:\n Der Webserver akzeptiert eine Anfrage von einem Webclient und bestimmt, ob sie vom PL/SQL-Gateway verarbeitet werden soll.\n\n Schritt 2:\n Das PL/SQL-Gateway verarbeitet die Anfrage, indem es den angeforderten Paketnamen, die Prozedur und die Variablen extrahiert.\n\n Schritt 3:\n Das angeforderte Paket und die Prozedur werden in einen anonymen PL/SQL-Block verpackt und an den Datenbankserver gesendet.\n\n Schritt 4:\n Der Datenbankserver führt die Prozedur aus und sendet die Ergebnisse als HTML an das Gateway zurück\n\n Schritt 5:\n Das Gateway sendet die Antwort über den Webserver zurück an den Client.\n\n Es ist wichtig, diesen Punkt zu verstehen – der PL/SQL-Code existiert nicht auf dem Webserver, sondern auf dem Datenbankserver.\n Das bedeutet, dass jede Schwachstelle im PL/SQL-Gateway oder jede Schwachstelle in der PL/SQL-Anwendung, wenn sie ausgenutzt wird, einem Angreifer direkten Zugriff auf den Datenbankserver verschafft.",
|
||||
"005_2": "SQL-Injection-Schwachstellen treten immer dann auf, wenn Eingaben beim Erstellen einer SQL-Abfrage verwendet werden, ohne dass sie angemessen eingeschränkt oder bereinigt wurden.\n Der MySQL-Server weist einige Besonderheiten auf, sodass einige Exploits speziell für diese Anwendung angepasst werden müssen.\n\n Wenn eine SQL-Injection-Schwachstelle in einer Anwendung gefunden wird, die von einer MySQL-Datenbank unterstützt wird, gibt es eine Reihe von Angriffen, die je nach MySQL-Version und Benutzerberechtigungen auf DBMS durchgeführt werden können.\n\n MySQL wird mit mindestens vier Versionen geliefert, die weltweit in der Produktion verwendet werden. Jede Version hat eine Reihe von Funktionen, die proportional zur Versionsnummer sind:\n • Ab Version 4.0: UNION\n • Ab Version 4.1: Subqueries\n • Ab Version 5.0: Stored Procedures, Stored Functions und die View mit dem Namen INFORMATION_SCHEMA\n • Ab Version 5.0.2: Trigger\n\n Es ist zu beachten, dass für MySQL-Versionen vor 4.0.x nur Boolean- oder zeitbasierte Blind-Injection-Angriffe verwendet werden konnten, da die Subquery-Funktionalität oder UNION-Anweisungen nicht implementiert waren.",
|
||||
"005_3": "SQL-Injection ermöglicht einem Angreifer den Zugriff auf die SQL-Server und die Ausführung von SQL-Code unter den Rechten des Benutzers, der für die Verbindung zur Datenbank verwendet wird. SQL-Injection-Techniken für Microsoft SQL Server verwenden spezifische Features.\n\n Wie in SQL-Injection erläutert, erfordert ein SQL-Injection-Exploit zwei Dinge: einen Einstiegspunkt und einen Exploit zum Eintreten.\n Jeder benutzergesteuerte Parameter, der von der Anwendung verarbeitet wird, kann eine Schwachstelle verbergen. Das beinhaltet:\n • Anwendungsparameter in Abfragezeichenfolgen (z. B. GET-Anfragen)\n • Anwendungsparameter, die Teil des Hauptteils einer POST-Anfrage sind\n • Browserbezogene Informationen (z. B. User-Agent, Referrer)\n • Hostbezogene Informationen (z. B. Hostname, IP)\n • Sitzungsbezogene Informationen (z. B. Benutzer-ID, Cookies)\n\n Einige Microsoft SQL Server-Operatoren und -Befehle sind:\n • Kommentaroperator --\n • Abfragetrennzeichen ;\n\n Zu den nützlichen gespeicherten Prozeduren gehören:\n • xp_cmdshell\n • xp_regread\n • xp_regwrite\n • sp_configure\n • sp_ makewebtask\n • sp_sendmail",
|
||||
"005_4": "Wenn eine SQL-Injection gefunden wurde, müssen Sie die Backend-Datenbank-Engine sorgfältig mit einem Fingerabdruck versehen. Sie können feststellen, dass die Back-End-Datenbank-Engine PostgreSQL ist, indem Sie den :: cast-Operator verwenden.\n Außerdem kann die Funktion version() verwendet werden, um das PostgreSQL-Banner abzurufen. Dies zeigt auch den Typ und die Version des zugrunde liegenden Betriebssystems an.\n\n SQL-Injection-Techniken für PostgreSQL haben die folgenden Merkmale:\n • PHP Connector ermöglicht die Ausführung mehrerer Anweisungen mit ; als Anweisungstrenner\n • SQL-Anweisungen können durch Anhängen des Kommentarzeichens abgeschnitten werden: --\n • LIMIT und OFFSET können in einer SELECT-Anweisung verwendet werden, um einen Teil der von der Abfrage generierten Ergebnismenge abzurufen\n\n Bei blinden SQL-Injection-Angriffen sollten Sie die folgenden integrierten Funktionen berücksichtigen:\n • Zeichenfolgenlänge - LENGTH(str)\n • Einen Teilstring aus einem gegebenen String extrahieren – SUBSTR(str,index,offset)\n • Zeichenfolgendarstellung ohne einfache Anführungszeichen – CHR(101)||CHR(108)||CHR(111)",
|
||||
"005_5": "Microsoft Access kann bestimmte Features für SQL-Injection-Techniken nutzen.\n Leider unterstützt MS Access keine typischen Operatoren, die traditionell bei SQL-Injection-Tests verwendet werden, einschließlich:\n• Keine Kommentarzeichen\n• Keine gestapelten Abfragen\n• Kein LIMIT-Operator\n• Keine SLEEP- oder BENCHMARK-ähnlichen Operatoren\n• und viele andere\n\n Es gibt jedoch auch viele andere Funktionen, die beim Testen der SQL-Injection verwendet werden können, einschließlich, aber nicht beschränkt auf:\n • ASC: Ruft den ASCII-Wert eines als Eingabe übergebenen Zeichens ab\n • CHR: Ruft das Zeichen des als Eingabe übergebenen ASCII-Werts ab\n • LEN: Gibt die Länge des als Parameter übergebenen Strings zurück\n • IIF: Ist das IF-Konstrukt, z. IIF(1=1, 'a', 'b') gibt 'a' zurück\n • MID: Mit dieser Funktion können Sie Teilstrings extrahieren\n • TOP: Mit dieser Funktion können Sie die max. Anzahl der Ergebnisse\n • LAST: Diese Funktion wird verwendet, um nur die letzte Zeile eines Satzes auszuwählen\n\n In MS Access sind standardmäßig verschiedene Systemtabellen vorhanden, die möglicherweise zum Abrufen von Tabellennamen und Spalten verwendet werden können.\n Leider sind diese Tabellen in der Standardkonfiguration neuerer Versionen von MS Access-Datenbanken nicht zugänglich. Trotzdem ist es immer einen Versuch wert:\n • MSysObjects\n • MSysACEs\n • MSysAccessXML",
|
||||
"005_6": "NoSQL-Datenbanken bieten lockerere Konsistenzbeschränkungen als herkömmliche SQL-Datenbanken. Da weniger relationale Einschränkungen und Konsistenzprüfungen erforderlich sind, bieten NoSQL-Datenbanken häufig Leistungs- und Skalierungsvorteile.\n Da diese NoSQL-Injection-Angriffe jedoch in einer prozeduralen Sprache und nicht in der deklarativen SQL-Sprache ausgeführt werden können, sind die potenziellen Auswirkungen größer als bei herkömmlicher SQL-Injection.\n\n NoSQL-Datenbankaufrufe werden in der Programmiersprache der Anwendung, einem benutzerdefinierten API-Aufruf oder gemäß einer gängigen Konvention (z. B. XML, JSON, LINQ usw.) formatiert.\n\n Typischerweise werden NoSQL-Injection-Angriffe ausgeführt, bei denen die Angriffszeichenfolge analysiert, ausgewertet oder zu einem NoSQL-API-Aufruf verkettet wird.\n Zusätzliche Timing-Angriffe können für das Fehlen von Parallelitätsprüfungen innerhalb einer NoSQL-Datenbank relevant sein. Diese werden nicht von Injektionstests abgedeckt.\n\n Mittlerweile sind über 150 NoSQL-Datenbanken verfügbar, aber zum Zeitpunkt der Erstellung dieses Artikels ist MongoDB die am weitesten verbreitete NoSQL-Datenbank.\n\n Die MongoDB-API erwartet BSON-Aufrufe (Binary JSON) und enthält ein sicheres Tool zum Zusammenstellen von BSON-Abfragen. Laut MongoDB-Dokumentation sind jedoch deserialisierte JSON- und JavaScript-Ausdrücke in mehreren alternativen Abfrageparametern zulässig.\n Wenn ein Angreifer beispielsweise in der Lage wäre, die an den $where-Operator übergebenen Daten zu manipulieren, könnte dieser Angreifer willkürliches JavaScript einbinden, das als Teil der MongoDB-Abfrage ausgewertet wird.",
|
||||
"005_7": "ORM Injection ist ein Angriff mit SQL Injection gegen ein ORM-generiertes Datenzugriffsobjektmodell. Aus Sicht eines Testers ist dieser Angriff praktisch identisch mit einem SQL-Injection-Angriff.\nDie Injection-Schwachstelle existiert jedoch in Code, der vom ORM-Tool generiert wird.\n\n Ein ORM ist ein objektrelationales Mapping-Tool.\nEs wird verwendet, um die objektorientierte Entwicklung innerhalb der Datenzugriffsschicht von Softwareanwendungen, einschließlich Webanwendungen, zu beschleunigen. Zu den Vorteilen der Verwendung eines ORM-Tools gehören die schnelle Generierung einer Objektschicht zur Kommunikation mit einer relationalen Datenbank, standardisierte Codevorlagen für diese Objekte und normalerweise eine Reihe sicherer Funktionen zum Schutz vor SQL-Injection-Angriffen. Von ORM generierte Objekte können SQL oder in einigen Fällen eine Variante von SQL verwenden, um CRUD-Operationen auf einer Datenbank auszuführen.\n\n Zu den ORM-Tools gehören Hibernate für Java, NHibernate für .NET, ActiveRecord für Ruby on Rails, EZPDO für PHP und viele andere.\n\n ORM-Injection-Schwachstellen sind identisch mit SQL-Injection-Tests. In den meisten Fällen ist die Schwachstelle in der ORM-Schicht das Ergebnis von benutzerdefiniertem Code, der Eingabeparameter nicht ordnungsgemäß validiert.\n Die meisten ORM-Tools bieten sichere Funktionen, um Benutzereingaben zu umgehen.\nWenn diese Funktionen jedoch nicht verwendet werden und der Entwickler benutzerdefinierte Funktionen verwendet, die Benutzereingaben akzeptieren, kann es möglich sein, einen SQL-Injection-Angriff auszuführen.\n\n Zu den Mustern, nach denen im Code gesucht werden muss, gehören:\n • Mit SQL-Strings verkettete Eingabeparameter",
|
||||
"005_8": "Clientseitige SQL-Injection tritt auf, wenn eine Anwendung die Web-SQL-Datenbanktechnologie implementiert und die Eingabe nicht ordnungsgemäß validiert oder ihre Abfragevariablen nicht parametrisiert. Diese Datenbank wird mithilfe von JavaScript (JS)-API-Aufrufen manipuliert, z. B. openDatabase() , wodurch eine vorhandene Datenbank erstellt oder geöffnet wird.\n\nDas folgende Testszenario überprüft, ob eine ordnungsgemäße Eingabevalidierung durchgeführt wird. Wenn die Implementierung angreifbar ist, kann der Angreifer in der Datenbank gespeicherte Informationen lesen, ändern oder löschen.\n\nWenn die getestete Anwendung die Web SQL DB implementiert, werden im clientseitigen Kern die folgenden drei Aufrufe verwendet:\n• openDatabase()\n• transaction()\n• executeSQL()",
|
||||
"006": "Das Lightweight Directory Access Protocol (LDAP) wird verwendet, um Informationen über Benutzer, Hosts und viele andere Objekte zu speichern. Die LDAP-Injection ist ein serverseitiger Angriff, bei dem sensible Informationen über Benutzer und Hosts, die in einer LDAP-Struktur dargestellt sind, offengelegt, geändert oder eingefügt werden können. Dies erfolgt durch Manipulieren von Eingabeparametern, die anschließend an interne Such-, Hinzufügungs- und Änderungsfunktionen übergeben werden.\n Eine Webanwendung könnte LDAP verwenden, damit sich Benutzer innerhalb einer Unternehmensstruktur authentifizieren oder die Informationen anderer Benutzer durchsuchen können.\n\n Das Ziel von LDAP-Injection-Angriffen besteht darin, Metazeichen von LDAP-Suchfiltern in eine Abfrage einzufügen, die von der Anwendung ausgeführt wird.\n [Rfc2254] definiert eine Grammatik zum Aufbau eines Suchfilters auf LDAPv3 und erweitert [Rfc1960] (LDAPv2).\nEin LDAP-Suchfilter wird in polnischer Schreibweise erstellt, die auch als [Präfixschreibweise] bekannt ist.\n\n Eine erfolgreiche Ausnutzung einer LDAP-Injection-Schwachstelle könnte dem Tester Folgendes ermöglichen:\n • Greifen Sie auf nicht autorisierte Inhalte zu\n • Anwendungseinschränkungen umgehen\n • Sammeln Sie nicht autorisierte Informationen\n • Hinzufügen oder Ändern von Objekten innerhalb der LDAP-Baumstruktur",
|
||||
"007": "Beim XML-Injektionstest versucht ein Tester, ein XML-Dokument in die Anwendung einzufügen. Wenn der XML-Parser die Daten nicht kontextbezogen validieren kann, ergibt der Test ein positives Ergebnis.\n\n Schritt 1:\n Um eine Anwendung auf das Vorhandensein einer XML-Injection-Schwachstelle zu testen, besteht der Versuch, XML-Metazeichen einzufügen.\n\n XML-Metazeichen sind:\n • Einfaches Anführungszeichen: ‘ \n • Doppeltes Anführungszeichen: “ \n • Spitze Klammern: > und <\n • Kommentar-Tag: <!--/-->\n • Et-Zeichen: &\n • Trennzeichen für CDATA-Abschnitte: <![CDATA[ / ]]>\n\n Ein weiterer Test bezieht sich auf das CDATA-Tag. Angenommen, das XML-Dokument wird verarbeitet, um eine HTML-Seite zu generieren. In diesem Fall können die CDATA-Abschnittsbegrenzer einfach eliminiert werden, ohne ihren Inhalt weiter zu prüfen. Dann ist es möglich, HTML-Tags einzufügen, die in die generierte Seite eingefügt werden, wobei vorhandene Bereinigungsroutinen vollständig umgangen werden.\n\n Schritt 2:\n Sobald der erste Schritt abgeschlossen ist, verfügt der Tester über einige Informationen über die Struktur des XML-Dokuments. Anschließend kann versucht werden, XML-Daten und -Tags einzufügen (Tag Injection).",
|
||||
"008": "Webserver geben Entwicklern normalerweise die Möglichkeit, kleine Teile dynamischen Codes in statische HTML-Seiten einzufügen. Diese Funktion wird durch die Server-Side Includes (SSI) verkörpert.\nBeim SSI-Injection-Test testen wir, ob es möglich ist, Daten in die Anwendung einzuspeisen, die von SSI-Mechanismen interpretiert werden. Eine erfolgreiche Ausnutzung dieser Schwachstelle ermöglicht es einem Angreifer, Code in HTML-Seiten einzuschleusen oder sogar eine Remotecodeausführung durchzuführen.\n\n In Bezug auf die SSI-Injektion könnte der Angreifer Eingaben bereitstellen, die, wenn sie von der Anwendung (oder vielleicht direkt vom Server) in eine dynamisch generierte Seite eingefügt würden, als eine oder mehrere SSI-Anweisungen geparst würden.\n\n Schritt 1:\n Was wir herausfinden müssen, ist, ob der Webserver tatsächlich SSI-Anweisungen unterstützt. Um das herauszufinden, müssen wir nur herausfinden, welche Art von Webserver auf unserem Ziel läuft.\n Hinweis: Wenn die Site .shtml-Dateien enthält, werden wahrscheinlich SSI unterstützt, da diese Erweiterung verwendet wird, um Seiten zu identifizieren, die diese Anweisungen enthalten.\n\n Schritt 2:\n Der nächste Schritt besteht darin, festzustellen, ob ein SSI-Injection-Angriff tatsächlich möglich ist und wenn ja, über welche Eingabepunkte können wir unseren Schadcode einschleusen.\n Wir müssen jede Seite finden, auf der der Benutzer Eingaben vornehmen darf, und überprüfen, ob die Anwendung die übermittelten Eingaben korrekt validiert.\n Wenn die Bereinigung unzureichend ist, müssen wir testen, ob wir Daten bereitstellen können, die unverändert angezeigt werden.\n Neben den üblichen vom Benutzer bereitgestellten Daten sind HTTP-Anforderungsheader und Cookie-Inhalte Eingabevektoren, die immer berücksichtigt werden sollten.\n\n Schritt 3:\n Sobald wir eine Liste möglicher Injektionspunkte haben, können wir überprüfen, wie die Eingabe behandelt wird, welche Art von Filterung durchgeführt wird, welche Zeichen die Anwendung nicht durchlässt und wie viele Codierungsarten berücksichtigt werden.",
|
||||
"009": "Webanwendungen verwenden Datenbanken stark zum Speichern und Zugreifen auf die Daten, die sie für ihren Betrieb benötigen.\n So wie auf relationale Datenbanken über die SQL-Sprache zugegriffen wird, verwenden XML-Datenbanken XPath als Standardabfragesprache.\n\n XPath ist eine Sprache, die hauptsächlich entworfen und entwickelt wurde, um Teile eines XML-Dokuments zu adressieren. Beim XPath-Injection-Test testen wir, ob es möglich ist, XPath-Syntax in eine von der Anwendung interpretierte Anfrage einzufügen, sodass ein Angreifer benutzergesteuerte XPath-Abfragen ausführen kann.\n XPath ist sogar noch leistungsfähiger als Standard-SQL, da seine gesamte Leistungsfähigkeit bereits in seinen Spezifikationen vorhanden ist, während eine große Anzahl der Techniken, die bei einem SQL-Injection-Angriff verwendet werden können, von den Eigenschaften des SQL-Dialekts abhängen, der von der Zieldatenbank verwendet wird.\n\n Das XPath-Angriffsmuster ist der üblichen SQL-Injektion sehr ähnlich, und wie bei einem gewöhnlichen SQL-Injection-Angriff besteht der erste Schritt bei der XPath-Injektion darin, ein einfaches Anführungszeichen (') in das zu testende Feld einzufügen, wodurch ein Syntaxfehler in das Feld eingeführt wird abzufragen und zu prüfen, ob die Anwendung eine Fehlermeldung zurückgibt.",
|
||||
"010": "Diese Bedrohung betrifft alle Anwendungen, die mit Mailservern (IMAP/SMTP) kommunizieren, im Allgemeinen Webmail-Anwendungen. Das Ziel dieses Tests besteht darin, die Fähigkeit zu überprüfen, beliebige IMAP/SMTP-Befehle in die Mailserver einzufügen, da Eingabedaten nicht ordnungsgemäß bereinigt werden.\n\n Eine IMAP/SMTP-Injection ermöglicht den Zugriff auf einen Mailserver, der sonst nicht direkt aus dem Internet erreichbar wäre. In einigen Fällen verfügen diese internen Systeme nicht über das gleiche Maß an Infrastruktursicherheit und Härtung, das auf die Front-End-Webserver angewendet wird. Daher sind Mailserver-Ergebnisse möglicherweise anfälliger für Angriffe durch Endbenutzer.\n\n Die Standardangriffsmuster sind:\n • Identifizieren anfälliger Parameter\n • Verstehen des Datenflusses und der Bereitstellungsstruktur des Clients\n • IMAP/SMTP-Befehlsinjektion\n\n Diese letzte Phase hat zwei mögliche Ergebnisse:\n\n Ergebnis 1:\n Die Injektion ist in einem nicht authentifizierten Zustand möglich: Die betroffene Funktionalität erfordert keine Authentifizierung des Benutzers.\n Die verfügbaren injizierten (IMAP)-Befehle sind beschränkt auf: \nCAPABILITY, NOOP, AUTHENTICATE, LOGIN und LOGOUT.\n\n Ergebnis 2:\n Die Injektion ist nur in einem authentifizierten Zustand möglich: Die erfolgreiche Ausnutzung erfordert, dass der Benutzer vollständig authentifiziert ist, bevor der Test fortgesetzt werden kann.\n\n In jedem Fall sieht der typische Aufbau einer IMAP/SMTP-Injection wie folgt aus:\n • Header: Ende des erwarteten Befehls;\n • Body: Injektion des neuen Befehls;\n • Footer: Anfang des erwarteten Befehls.",
|
||||
"011": "Beim Code-Injection-Test übermittelt ein Tester Eingaben, die vom Webserver als dynamischer Code oder als eingebundene Datei verarbeitet werden. Diese Tests können auf verschiedene serverseitige Scripting-Engines abzielen, z. B. ASP oder PHP. Zum Schutz vor diesen Angriffen müssen eine ordnungsgemäße Eingabevalidierung und sichere Codierungspraktiken angewendet werden.\n\n Testen auf PHP-Injection-Schwachstellen\n Unter Verwendung der Abfragezeichenfolge kann der Tester Code einfügen, der als Teil der enthaltenen Datei verarbeitet werden soll. Die schädliche URL wird als Parameter für die PHP-Seite akzeptiert, die später den Wert in einer eingebundenen Datei verwendet.\n\n Testen auf ASP-Code-Injection-Schwachstellen\n Untersuchen Sie den ASP-Code auf Benutzereingaben, die in Ausführungsfunktionen verwendet werden.\nKann der Benutzer Befehle in das Dateneingabefeld eingeben?",
|
||||
"011_1": "Die Schwachstelle „File Inclusion“ ermöglicht es einem Angreifer, eine Datei einzufügen, wobei er normalerweise einen „dynamischen Dateieinschluss“-Mechanismus ausnutzt, der in der Zielanwendung implementiert ist. Die Sicherheitsanfälligkeit tritt aufgrund der Verwendung von Benutzereingaben ohne ordnungsgemäße Überprüfung auf.\n\n Dies kann dazu führen, dass der Inhalt der Datei ausgegeben wird, aber je nach Schweregrad kann es auch zu Folgendem führen:\n • Codeausführung auf dem Webserver\n • Code-Ausführung auf der Client-Seite wie JavaScript, was zu anderen Angriffen wie Cross-Site-Scripting (XSS) führen kann.\n • Dienstverweigerung (DoS)\n • Offenlegung sensibler Informationen\n\n Local File Inclusion (auch bekannt als LFI) ist der Prozess des Einschließens von Dateien, die bereits lokal auf dem Server vorhanden sind, durch Ausnutzung von angreifbaren Einschlussverfahren.\n Da LFI auftritt, wenn Pfade, die an „include“-Anweisungen übergeben werden, nicht ordnungsgemäß bereinigt werden, sollten wir in einem Blackbox-Testansatz nach Skripten suchen, die Dateinamen als Parameter verwenden.",
|
||||
"011_2": "Die Schwachstelle „File Inclusion“ ermöglicht es einem Angreifer, eine Datei einzufügen, wobei er normalerweise einen „dynamischen Dateieinschluss“-Mechanismus ausnutzt, der in der Zielanwendung implementiert ist. Die Sicherheitsanfälligkeit tritt aufgrund der Verwendung von Benutzereingaben ohne ordnungsgemäße Überprüfung auf.\n\n Dies kann dazu führen, dass der Inhalt der Datei ausgegeben wird, aber je nach Schweregrad kann es auch zu Folgendem führen:\n • Codeausführung auf dem Webserver\n • Code-Ausführung auf der Client-Seite wie JavaScript, was zu anderen Angriffen wie Cross-Site-Scripting (XSS) führen kann.\n • Dienstverweigerung (DoS)\n • Offenlegung sensibler Informationen\n\n Remote File Inclusion (auch bekannt als RFI) ist der Prozess des Einschließens von Remote-Dateien durch die Ausnutzung von anfälligen Einschlussverfahren.\n\n Da RFI auftritt, wenn Pfade, die an „include“-Anweisungen übergeben werden, nicht ordnungsgemäß bereinigt werden, sollten wir in einem Blackbox-Testansatz nach Skripten suchen, die Dateinamen als Parameter verwenden.",
|
||||
"012": "OS Command Injection ist eine Technik, die über eine Webschnittstelle verwendet wird, um OS-Befehle auf einem Webserver auszuführen. Der Benutzer liefert Betriebssystembefehle über eine Webschnittstelle, um OS-Befehle auszuführen. Jede nicht ordnungsgemäß bereinigte Weboberfläche ist von diesem Exploit betroffen.\n\n Beim Anzeigen einer Datei in einer Webanwendung wird der Dateiname häufig in der URL angezeigt. Perl ermöglicht die Weiterleitung von Daten aus einem Prozess in eine offene Anweisung. Der Benutzer kann einfach das Pipe-Symbol „|“ anhängen. am Ende des Dateinamens.\n Das Anhängen eines Semikolons an das Ende einer URL für eine .PHP-Seite, gefolgt von einem Betriebssystembefehl, führt den Befehl aus. %3B ist URL-kodiert und wird in Semikolon dekodiert.",
|
||||
"013": "Eine Format String ist eine mit Null endende Zeichenfolge, die auch Konvertierungsspezifizierer enthält, die zur Laufzeit interpretiert oder konvertiert werden. Wenn serverseitiger Code die Eingabe eines Benutzers mit einer Formatzeichenfolge verkettet, kann ein Angreifer zusätzliche Konvertierungsspezifizierer anhängen, um einen Laufzeitfehler, die Offenlegung von Informationen oder einen Pufferüberlauf zu verursachen.\n\nBewerten Sie, ob das Einfügen von Konvertierungsspezifizierern für Formatzeichenfolgen in benutzergesteuerte Felder zu unerwünschtem Verhalten der Anwendung führt.\n\nDer schlimmste Fall von Sicherheitslücken bei Formatzeichenfolgen tritt in Sprachen auf, die keine Argumente prüfen und außerdem einen %n-Spezifizierer enthalten, der in den Speicher schreibt. Wenn diese Funktionen von einem Angreifer ausgenutzt werden, der eine Formatzeichenfolge ändert, kann dies zur Offenlegung von Informationen und zur Codeausführung führen:\n• C und C++ printf und ähnliche Methoden fprintf, sprintf, snprintf\n• Perl printf und sprintf\n\nDiese Formatzeichenfolgenfunktionen können nicht in den Speicher schreiben, Angreifer können jedoch dennoch die Offenlegung von Informationen verursachen, indem sie Formatzeichenfolgen so ändern, dass sie Werte ausgeben, die die Entwickler nicht senden wollten.\nDie folgenden Format String Funktionen können Laufzeitfehler verursachen, wenn der Angreifer Konvertierungsspezifizierer hinzufügt:\n• Java String.format und PrintStream.format\n• PHP printf\n\nZu den Tests gehören die Analyse des Codes und das Einfügen von Konvertierungsspezifizierern als Benutzereingabe in die zu testende Anwendung.",
|
||||
"014": "Inkubationstests werden auch oft als dauerhafte Angriffe bezeichnet und sind eine komplexe Testmethode, die mehr als eine Schwachstelle zur Datenvalidierung benötigt, um zu funktionieren.\n Inkubierte Schwachstellen werden normalerweise verwendet, um „Watering Hole“-Angriffe gegen Benutzer legitimer Webanwendungen durchzuführen.\n\n Inkubierte Schwachstellen haben die folgenden Merkmale:\n\n Zuerst:\n Der Angriffsvektor muss in erster Linie persistiert werden, er muss in der Persistenzschicht gespeichert werden, und dies würde nur auftreten, wenn eine schwache Datenvalidierung vorhanden wäre oder die Daten über einen anderen Kanal wie eine Verwaltungskonsole oder direkt in das System gelangen über einen Backend-Batch-Prozess.\n\n Zweitens:\n Sobald der Angriffsvektor „zurückgerufen“ wurde, musste der Vektor erfolgreich ausgeführt werden. Beispielsweise würde ein inkubierter XSS-Angriff eine schwache Ausgabevalidierung erfordern, damit das Skript in seiner ausführbaren Form an den Client geliefert wird.\n\n Die Ausnutzung einiger Schwachstellen oder sogar Funktionsmerkmale einer Webanwendung ermöglicht es einem Angreifer, Daten einzuschleusen, die später abgerufen werden.\n In einem Penetrationstest können inkubierte Angriffe verwendet werden, um die Kritikalität bestimmter Fehler zu bewerten, die normalerweise verwendet werden, um eine große Anzahl von Opfern gleichzeitig anzugreifen.\n\n Diese Art von asynchronen Angriffen deckt ein großes Spektrum an Angriffsvektoren ab, darunter die folgenden:\n • Datei-Upload-Komponenten in einer Webanwendung\n • Cross-Site-Scripting-Probleme in öffentlichen Forenbeiträgen\n • SQL/XPATH-Injection, die es dem Angreifer ermöglicht, Inhalte in eine Datenbank hochzuladen\n • Falsch konfigurierte Server, die die Installation von Paketen oder Komponenten ermöglichen\n\n Schritt 1:\n Überprüfen Sie den Inhaltstyp, der zum Hochladen in die Webanwendung zugelassen ist, und die resultierende URL für die hochgeladene Datei.\n\n Schritt 2:\n Laden Sie eine Datei hoch, die eine Komponente auf der lokalen Benutzerarbeitsstation ausnutzt, wenn sie vom Benutzer angezeigt oder heruntergeladen wird.\n\n Schritt 3:\n Senden Sie Ihrem Opfer eine E-Mail oder eine andere Art von Benachrichtigung, um ihn/sie dazu zu bringen, die Seite zu durchsuchen.\n\n Das erwartete Ergebnis ist, dass der Exploit ausgelöst wird, wenn der Benutzer die resultierende Seite durchsucht oder die Datei von der vertrauenswürdigen Site herunterlädt und ausführt.",
|
||||
"015": "Es gibt zwei verschiedene Angriffe, die auf bestimmte HTTP-Header abzielen:\n• HTTP-Splitting\n• HTTP-Smuggling\n\n Der erste Angriff nutzt einen Mangel an Eingabebereinigung aus, wodurch ein Eindringling CR- und LF-Zeichen in die Header der Anwendungsantwort einfügen und diese Antwort in zwei verschiedene HTTP-Nachrichten „aufteilen“ kann.\n Das Ziel des Angriffs kann von Cache-Poisoning bis hin zu Cross-Site-Scripting reichen.\n\n Beim zweiten Angriff nutzt der Angreifer die Tatsache aus, dass einige speziell gestaltete HTTP-Nachrichten je nach Agent, der sie empfängt, auf unterschiedliche Weise analysiert und interpretiert werden können.\nHTTP-Schmuggel erfordert ein gewisses Maß an Wissen über die verschiedenen Agenten, die die HTTP-Nachrichten verarbeiten (Webserver, Proxy, Firewall).\n\n HTTP-Splitting\n Einige Webanwendungen verwenden einen Teil der Benutzereingaben, um die Werte einiger Header ihrer Antworten zu generieren. Das einfachste Beispiel sind Umleitungen, bei denen die Ziel-URL von einem vom Benutzer übermittelten Wert abhängt.\n Die Header, die die wahrscheinlichsten Kandidaten für diesen Angriff sind, sind:\n• Location\n• Set-Cookie\n\n HTTP-Smuggling\n Dies nutzt die verschiedenen Möglichkeiten, wie eine speziell gestaltete HTTP-Nachricht von verschiedenen Agenten (Browsern, Webcaches, Anwendungsfirewalls) analysiert und interpretiert werden kann.",
|
||||
"016": "In diesem Abschnitt wird beschrieben, wie Sie alle eingehenden/ausgehenden HTTP-Anfragen sowohl auf der Client- als auch auf der Serverseite überwachen. Der Zweck dieser Tests besteht darin, zu überprüfen, ob im Hintergrund unnötige oder verdächtige HTTP-Anfragen gesendet werden.\n\nDie meisten Web-Sicherheitstesttools (z. B. AppScan, BurpSuite, ZAP) fungieren als HTTP-Proxy. Dies erfordert Änderungen des Proxys in der clientseitigen Anwendung oder im Browser. Die unten aufgeführten Testtechniken konzentrieren sich in erster Linie darauf, wie wir HTTP-Anfragen ohne Änderungen auf der Clientseite überwachen können, was eher dem Produktionsszenario entspricht.\n\nTestziele\n• Überwachen Sie alle eingehenden und ausgehenden HTTP-Anfragen an den Webserver, um verdächtige Anfragen zu untersuchen.\n• Überwachen Sie den HTTP-Verkehr ohne Änderungen am Browser-Proxy des Endbenutzers oder an der clientseitigen Anwendung.\n\nSo testen Sie\nEs gibt eine Situation, in der wir alle eingehenden HTTP-Anfragen auf dem Webserver überwachen möchten, aber die Konfiguration auf der Browser- oder Anwendungsclientseite nicht ändern können. In diesem Szenario können wir auf der Webserverseite einen Reverse-Proxy einrichten, um alle eingehenden/ausgehenden Anfragen auf dem Webserver zu überwachen:\n• Für die Windows-Plattform wird Fiddler empfohlen.\n• Für die Linux-Plattform kann Charles Web Debugging Proxy verwendet werden.\n\nDie Testschritte:\n1. Installieren Sie Fiddler oder Charles auf dem Webserver\n2. Konfigurieren Sie den Fiddler oder Charles als Reverse Proxy\n3. Erfassen Sie den HTTP-Verkehr\n4. Untersuchen Sie den HTTP-Verkehr\n5. Ändern Sie HTTP-Anforderungen und spielen Sie die geänderten Anforderungen zum Testen erneut ab",
|
||||
"017": "Ein Webserver hostet üblicherweise mehrere Webanwendungen unter derselben IP-Adresse und verweist über den virtuellen Host auf jede Anwendung. Bei einer eingehenden HTTP-Anfrage leiten Webserver die Anfrage häufig basierend auf dem im Host-Header bereitgestellten Wert an den virtuellen Zielhost weiter. Ohne ordnungsgemäße Validierung des Header-Werts kann der Angreifer ungültige Eingaben liefern, die den Webserver dazu veranlassen:\n• Senden Sie Anfragen an den ersten virtuellen Host in der Liste\n• eine Weiterleitung zu einer vom Angreifer kontrollierten Domäne verursachen\n• Web-Cache-Poisoning durchführen\n• die Funktionalität zum Zurücksetzen des Passworts manipulieren\n\nTestziele\n• Bewerten Sie, ob der Host-Header in der Anwendung dynamisch analysiert wird.\n• Umgehen Sie Sicherheitskontrollen, die auf dem Header basieren\n\nSo testen Sie\nDer erste Test ist so einfach wie die Angabe einer anderen Domain (z. B. attacker.com ) im Host-Header-Feld. Die Art und Weise, wie der Webserver den Header-Wert verarbeitet, bestimmt die Auswirkung. Der Angriff ist gültig, wenn der Webserver die Eingabe verarbeitet, um die Anforderung an einen vom Angreifer kontrollierten Host zu senden, der sich in der angegebenen Domäne befindet, und nicht an einen internen virtuellen Host, der sich auf dem Webserver befindet.\n\nWeitere Angriffe\n• X-Forwarded-Host-Header-Bypass\n• Web-Cache-Poisoning\n• Passwort-Reset-Poisoning",
|
||||
"018": "Webanwendungen nutzen üblicherweise serverseitige Template-Technologien (Jinja2, Twig, FreeMaker usw.), um dynamische HTML-Antworten zu generieren. Serverseitige Template-Injection-Schwachstellen (SSTI) treten auf, wenn Benutzereingaben auf unsichere Weise in eine Vorlage eingebettet werden und zur Remote-Codeausführung auf dem Server führen.\n\nAlle Funktionen, die erweitertes, vom Benutzer bereitgestelltes Markup unterstützen, können für SSTI anfällig sein, einschließlich Wiki-Seiten, Rezensionen, Marketinganwendungen, CMS-Systeme usw. Einige Template-Engines verwenden verschiedene Mechanismen (z. B. Sandbox, Zulassungsliste usw.), um vor SSTI zu schützen.\n\nTestziele\n• Erkennen Sie Schwachstellen bei der Template-Injection.\n• Identifizieren Sie die Template-Engine.\n• Erstellen Sie den Exploit.\n\nSo testen Sie\n• Identifizieren Sie die Schwachstelle durch Template-Injection\n• Identifizieren Sie die Templating Engine\n• Erstellen Sie den RCE-Exploit",
|
||||
"019": "Webanwendungen interagieren häufig mit internen oder externen Ressourcen. Während Sie davon ausgehen können, dass nur die vorgesehene Ressource die von Ihnen gesendeten Daten verarbeitet, kann eine unsachgemäße Verarbeitung der Daten dazu führen, dass Injektionsangriffe möglich sind. Eine Art von Injektionsangriff wird als Server-side Request Forgery (SSRF) bezeichnet.\n\nEin erfolgreicher SSRF-Angriff kann dem Angreifer Zugriff auf eingeschränkte Aktionen, interne Dienste oder interne Dateien innerhalb der Anwendung oder der Organisation gewähren. In einigen Fällen kann es sogar zu Remote Code Execution (RCE) kommen.\n\nTestziele\n• Identifizieren Sie SSRF-Injektionspunkte.\n• Testen Sie, ob die Einspritzpunkte ausnutzbar sind.\n• Bewertet den Schweregrad der Schwachstelle.\n\nSo testen Sie\n• Laden Sie den Inhalt einer Datei\n• Greifen Sie auf eine eingeschränkte Seite zu\n• Holen Sie sich eine lokale Datei\n\nÜbliche Filterumgehung\nManchmal lässt die Anwendung Eingaben zu, die einem bestimmten Ausdruck entsprechen, z. B. einer Domäne. Dies kann umgangen werden, wenn der URL-Schema-Parser nicht ordnungsgemäß implementiert ist, was zu Angriffen führt, die semantischen Angriffen ähneln.\n• Verwenden des @-Zeichens zur Trennung zwischen Benutzerinformationen und Host: https://expected-domain@attackerdomain\n• URL-Fragmentierung mit dem #-Zeichen: https://attacker-domain#expected-domain\n• URL-Kodierung\n• Fuzzing\n• Kombinationen aus allen oben genannten"
|
||||
},
|
||||
"err": {
|
||||
"001": "Während eines Penetrationstests für Webanwendungen stoßen wir häufig auf viele Fehlercodes, die von Anwendungen oder Webservern generiert werden.\n Es ist möglich, dass diese Fehler angezeigt werden, indem bestimmte Anfragen verwendet werden, die entweder speziell mit Tools erstellt oder manuell erstellt wurden. Diese Codes sind für Penetrationstester bei ihren Aktivitäten sehr nützlich, da sie viele Informationen über Datenbanken, Fehler und andere technologische Komponenten preisgeben, die direkt mit Webanwendungen verknüpft sind.\n\n Eine gute Sammlung von Fehlerinformationen kann die Bewertungseffizienz verbessern, indem die Gesamtzeit für die Durchführung des Penetrationstests verkürzt wird.\n Angreifer verwenden manchmal Suchmaschinen, um Fehler zu finden, die Informationen preisgeben. Es können Suchvorgänge durchgeführt werden, um fehlerhafte Websites als zufällige Opfer zu finden, oder es ist möglich, mit den Filterwerkzeugen der Suchmaschine nach Fehlern auf einer bestimmten Website zu suchen.\n\n Nachfolgend sind einige Bereiche aufgeführt, die dem Benutzer detaillierte Fehlermeldungen zurückgeben könnten. Jeder der Bereiche enthält spezifische Informationen über das Betriebssystem, die Anwendungsversion usw.\n • Webserverfehler (HTTP-Antworten)\n • Anwendungsserverfehler (Framework-Meldungen)\n • Datenbankfehler (Datenbanksystemmeldungen)",
|
||||
"002": "Stack-Traces sind an sich keine Schwachstellen, aber sie offenbaren oft Informationen, die für einen Angreifer interessant sind. Angreifer versuchen, diese Stack-Traces zu generieren, indem sie die Eingabe in die Webanwendung mit fehlerhaften HTTP-Anforderungen und anderen Eingabedaten manipulieren.\n\n Wenn die Anwendung mit nicht verwalteten Stack-Traces antwortet, können für Angreifer nützliche Informationen preisgegeben werden. Diese Informationen könnten dann für weitere Angriffe verwendet werden.\n\n Es gibt eine Vielzahl von Techniken, die dazu führen, dass Ausnahmemeldungen in einer HTTP-Antwort gesendet werden. Beachten Sie, dass dies in den meisten Fällen eine HTML-Seite ist, aber Ausnahmen können auch als Teil von SOAP- oder REST-Antworten gesendet werden.\nEinige Tests zum Ausprobieren umfassen:\n • Ungültige Eingabe\n • Eingaben, die nicht alphanumerische Zeichen oder Abfragesyntax enthalten\n • leere Eingänge\n • zu lange Eingaben\n • Zugriff auf interne Seiten ohne Authentifizierung\n • Umgehung des Anwendungsflusses\n\n Alle oben genannten Tests können zu Anwendungsfehlern führen, die Stack-Traces enthalten können. Es wird empfohlen, zusätzlich zu manuellen Tests einen Fuzzer zu verwenden.\n\n Wenn der SSL/TLS-Dienst vorhanden ist, ist er gut, aber er erhöht die Angriffsfläche und die folgenden Schwachstellen bestehen:\n • SSL/TLS-Protokolle, Chiffren, Schlüssel und Neuverhandlung müssen ordnungsgemäß konfiguriert sein\n • Zertifikatsgültigkeit muss gewährleistet sein"
|
||||
},
|
||||
"crypst": {
|
||||
"001": "Sensible Daten müssen geschützt werden, wenn sie durch das Netzwerk übertragen werden. \nAls Faustregel gilt: Wenn Daten bei der Speicherung geschützt werden müssen, müssen sie auch während der Übertragung geschützt werden.\n\n Verschiedene Arten von zu schützenden Informationen können auch im Klartext übertragen werden. Es kann überprüft werden, ob diese Informationen über HTTP statt HTTPS übertragen werden.\n\n HTTP ist ein Klartextprotokoll und wird normalerweise über einen SSL/TLS-Tunnel gesichert, was zu HTTPS-Datenverkehr führt. Server werden mit digitalen Zertifikaten authentifiziert, und es ist auch möglich, Client-Zertifikate für die gegenseitige Authentifizierung zu verwenden.\n Selbst wenn heute hochwertige Chiffren unterstützt und normalerweise verwendet werden, kann eine Fehlkonfiguration im Server dazu verwendet werden, die Verwendung einer schwachen Chiffre – oder schlimmstenfalls gar keine Verschlüsselung – zu erzwingen, die es einem Angreifer ermöglicht, Zugang zu dem vermeintlich sicheren Kommunikationskanal zu erhalten.\n\n Häufige Probleme:\n Wenn der SSL/TLS-Dienst vorhanden ist, ist er gut, aber er erhöht die Angriffsfläche und die folgenden Schwachstellen bestehen:\n • SSL/TLS-Protokolle, Chiffren, Schlüssel und Neuverhandlung müssen ordnungsgemäß konfiguriert sein\n • Zertifikatsgültigkeit muss gewährleistet sein\n • Offengelegte Software muss aufgrund möglicher bekannter Schwachstellen aktualisiert werden\n • Verwendung des Secure-Flags für Sitzungscookies\n • Verwendung von HTTP Strict Transport Security (HSTS)\n • Das Vorhandensein von HTTP und HTTPS, die zum Abfangen von Datenverkehr verwendet werden können\n • Das Vorhandensein gemischter HTTPS- und HTTP-Inhalte auf derselben Seite, die zum Leaking von Informationen verwendet werden können \n\n Prüfung auf sensible Daten, die im Klartext übertragen werden\n Ein typisches Beispiel ist die Verwendung der Basisauthentifizierung über HTTP, da bei der Basisauthentifizierung die Anmeldeinformationen nach der Anmeldung in HTTP-Header codiert – und nicht verschlüsselt – werden.\n\n Testen auf schwache SSL/TLS-Chiffren/Protokolle/Schlüssel-Schwachstellen\n Die große Anzahl verfügbarer Cipher Suites und der schnelle Fortschritt in der Kryptoanalyse machen das Testen eines SSL-Servers zu einer nicht trivialen Aufgabe. Zum Zeitpunkt des Schreibens sind diese Kriterien eine allgemein anerkannte Checkliste:\n • Schwache Chiffren dürfen nicht verwendet werden (z. B. weniger als 128 Bit)\n • Keine NULL-Ciphers-Suite, da keine Verschlüsselung verwendet wird\n • Schwache Protokolle müssen deaktiviert werden (z. B. muss SSLv2 deaktiviert werden)\n • Die Neuverhandlung muss ordnungsgemäß konfiguriert sein (z. B. muss die unsichere Neuverhandlung deaktiviert sein).\n • Keine Verschlüsselungssammlungen auf Exportebene (EXP), da diese leicht geknackt werden können\n • Die Schlüssellänge von X.509-Zertifikaten muss stark sein\n • X.509-Zertifikate dürfen nur mit sicheren Hash-Algorithmen signiert werden\n • Schlüssel müssen mit der richtigen Entropie generiert werden\n • Sichere Neuverhandlung sollte aktiviert sein.\n • MD5 sollte aufgrund bekannter Kollisionsangriffe nicht verwendet werden\n • RC4 sollte wegen kryptoanalytischer Angriffe nicht verwendet werden\n • Der Server sollte vor BEAST-Angriffen geschützt werden\n • Der Server sollte vor CRIME-Angriffen geschützt werden, die TLS-Komprimierung muss deaktiviert werden\n • Der Server sollte Forward Secrecy unterstützen",
|
||||
"002": "Ein Padding-Oracle ist eine Funktion einer Anwendung, die vom Client bereitgestellte verschlüsselte Daten entschlüsselt, z. interner Sitzungsstatus, der auf dem Client gespeichert ist, und gibt den Status der Gültigkeit der Auffüllung nach der Entschlüsselung preis.\n\n Die Existenz eines Padding-Oracles ermöglicht es einem Angreifer, verschlüsselte Daten zu entschlüsseln und willkürliche Daten zu verschlüsseln, ohne den Schlüssel zu kennen, der für diese kryptografischen Operationen verwendet wird.\n\n Blockchiffren verschlüsseln Daten nur in Blöcken bestimmter Größe. Die von gängigen Chiffren verwendeten Blockgrößen sind 8 und 16 Bytes. Daten, deren Größe nicht mit einem Vielfachen der Blockgröße der verwendeten Chiffre übereinstimmt, müssen auf bestimmte Weise aufgefüllt werden, damit der Entschlüsseler die Auffüllung entfernen kann.\n\n Der Padding-Oracle-Angriff ermöglicht es einem Angreifer, verschlüsselte Daten ohne Kenntnis des Verschlüsselungsschlüssels und der verwendeten Chiffre zu entschlüsseln, indem er geschickt manipulierte Chiffriertexte an das Padding-Oracle sendet und die von ihm zurückgegebenen Ergebnisse beobachtet. Dies führt zu einem Verlust der Vertraulichkeit der verschlüsselten Daten.\n Ein Padding-Oracle-Angriff ermöglicht es einem Angreifer auch, beliebige Klartexte ohne Kenntnis des verwendeten Schlüssels und der Chiffre zu verschlüsseln.\n\n Zunächst müssen die möglichen Eingabepunkte für ein Padding-Oracle identifiziert werden. Generell müssen folgende Bedingungen erfüllt sein:\n\n Bedingung 1:\n Die Daten sind verschlüsselt. Gute Kandidaten sind Werte, die zufällig erscheinen.\n\n Bedingung 2:\n Es wird eine Blockchiffre verwendet. Die Länge des decodierten (z. B. Base64) Chiffriertextes ist ein Vielfaches der üblichen Chiffrierblockgrößen wie 8 oder 16 Bytes. Verschiedene Chiffriertexte haben einen gemeinsamen Teiler in der Länge.\n\n Wenn ein solcher Eingabewertkandidat identifiziert wird, sollte das Verhalten der Anwendung gegenüber einer bitweisen Manipulation des verschlüsselten Werts überprüft werden.\n Die Tests und der Basiswert sollten mindestens drei verschiedene Zustände während und nach der Entschlüsselung bewirken:\n • Geheimtext wird entschlüsselt, Ergebnisdaten sind korrekt\n • Chiffrierter Text wird entschlüsselt, resultierende Daten werden verstümmelt und verursachen eine Ausnahme- oder Fehlerbehandlung in der Anwendungslogik\n • Die Chiffretext-Entschlüsselung schlägt aufgrund von Padding-Fehlern fehl\n\n Suchen Sie insbesondere nach Ausnahmen und Meldungen, die besagen, dass etwas mit dem Padding nicht stimmt. Wenn die drei oben beschriebenen unterschiedlichen Zustände implizit beobachtbar sind (unterschiedliche Fehlermeldungen, Timing-Seitenkanäle), liegt mit hoher Wahrscheinlichkeit an dieser Stelle ein Padding-Oracle vor. Beispiele:\n • ASP.NET löst „System.Security.Cryptography.Cryptographic Exception: Padding is invalid and can not be remove“ aus.\n • In Java wird in diesem Fall eine javax.crypto.BadPaddingException geworfen\n • Entschlüsselungsfehler oder ähnliches können mögliche padding oracles sein",
|
||||
"003": "Sensible Daten müssen geschützt werden, wenn sie durch das Netzwerk übertragen werden. Wenn Daten über HTTPS übertragen oder auf andere Weise verschlüsselt werden, darf der Schutzmechanismus keine Einschränkungen oder Schwachstellen aufweisen.\n\n Als Faustregel gilt: Wenn Daten bei der Speicherung geschützt werden müssen, müssen diese Daten auch bei der Übertragung geschützt werden. \n Einige Beispiele für sensible Daten sind:\n • Bei der Authentifizierung verwendete Informationen (z. B. Anmeldeinformationen, PINs, Tokens, Cookies …)\n • Informationen, die durch Gesetze, Vorschriften oder spezifische Unternehmensrichtlinien geschützt sind (z. B. Kreditkarten, Kundendaten)\n\n Verschiedene Arten von Informationen, die geschützt werden müssen, könnten von der Anwendung im Klartext übertragen werden. Es kann überprüft werden, ob diese Informationen über HTTP statt HTTPS übertragen werden oder ob schwache Chiffren verwendet werden.\n\n 1. Basisauthentifizierung über HTTP\n Ein typisches Beispiel ist die Verwendung von Basic Authentication über HTTP. Bei Verwendung der Standardauthentifizierung werden Benutzeranmeldeinformationen codiert und nicht verschlüsselt und als HTTP-Header gesendet.\n\n 2. Formularbasierte Authentifizierung über HTTP durchgeführt\n Ein weiteres typisches Beispiel sind Authentifizierungsformulare, die Anmeldeinformationen zur Benutzerauthentifizierung über HTTP übertragen. Es ist möglich, dieses Problem zu sehen, indem Sie den HTTP-Datenverkehr mit einem Interception-Proxy untersuchen.\n\n 3. Cookie mit Sitzungs-ID, das über HTTP gesendet wird\n Das Session-ID-Cookie muss über geschützte Kanäle übertragen werden. Wenn für das Cookie kein sicheres Flag gesetzt ist, ist es der Anwendung gestattet, es unverschlüsselt zu übertragen.",
|
||||
"004": "Die falsche Verwendung von Verschlüsselungsalgorithmen kann zur Offenlegung vertraulicher Daten, zum Verlust von Schlüsseln, zur fehlerhaften Authentifizierung, zu unsicheren Sitzungen und zu Spoofing-Angriffen führen. Es gibt einige Verschlüsselungs- oder Hash-Algorithmen, von denen bekannt ist, dass sie schwach sind und deren Verwendung nicht empfohlen wird, beispielsweise MD5 und RC4.\n\nNeben der richtigen Auswahl sicherer Verschlüsselungs- oder Hash-Algorithmen ist auch die richtige Verwendung von Parametern für das Sicherheitsniveau von Bedeutung. Beispielsweise wird der ECB-Modus (Electronic Code Book) nicht für die Verwendung bei der asymmetrischen Verschlüsselung empfohlen.\n\nTestziele\n• Bereitstellung einer Richtlinie zur Identifizierung schwacher Verschlüsselungs- oder Hashing-Anwendungen und -Implementierungen.\n\nGrundlegende Sicherheitscheckliste\n• Bei Verwendung von AES128 oder AES256 muss der IV (Initialisierungsvektor) zufällig und unvorhersehbar sein.\n• Für asymmetrische Verschlüsselung verwenden Sie vorzugsweise Elliptic Curve Cryptography (ECC) mit einer sicheren Kurve wie Curve25519.\n• Bei Verwendung von RSA in der Signatur wird PSS-Padding empfohlen.\n• Schwache Hash-/Verschlüsselungsalgorithmen wie MD5, RC4, DES, Blowfish, SHA1 sollten nicht verwendet werden.\n• Passwort-Hashing: PBKDF2, Scrypt, Bcrypt\n• Verwendungen von SSH, CBC-Modus sollten nicht verwendet werden.\n• Wenn ein symmetrischer Verschlüsselungsalgorithmus verwendet wird, sollte der ECB-Modus (Electronic Code Book) nicht verwendet werden.\n• Wenn PBKDF2 zum Hashen von Passwörtern verwendet wird, wird empfohlen, dass der Iterationsparameter über 10.000 liegt."
|
||||
},
|
||||
"buslogic": {
|
||||
"001": "Die Anwendung muss sicherstellen, dass nur logisch gültige Daten sowohl am Frontend als auch direkt auf der Serverseite eines Anwendungssystems eingegeben werden können. Daten nur lokal zu verifizieren, kann Anwendungen anfällig für Serverinjektionen durch Proxys oder bei Übergaben an andere Systeme machen. Dies unterscheidet sich von der einfachen Durchführung einer Boundary Value Analysis (Grenzwertanalyse) dadurch, dass sie schwieriger ist und in den meisten Fällen nicht einfach am Eingangspunkt überprüft werden kann, sondern normalerweise die Überprüfung eines anderen Systems erfordert.\n\n Schwachstellen im Zusammenhang mit der Geschäftsdatenvalidierung sind insofern einzigartig, als sie anwendungsspezifisch sind und sich von den Schwachstellen im Zusammenhang mit gefälschten Anforderungen darin unterscheiden, dass sie sich mehr um logische Daten kümmern, anstatt einfach den Arbeitsablauf der Geschäftslogik zu unterbrechen.\n\n Das Front-End und das Back-End der Anwendung sollten überprüfen und validieren, dass die Daten, die sie hat, verwendet und weitergibt, logisch gültig sind. Selbst wenn der Benutzer einer Anwendung gültige Daten bereitstellt, kann die Geschäftslogik dazu führen, dass sich die Anwendung je nach Daten oder Umständen anders verhält.\n\n Generische Testmethode\n • Überprüfen Sie die Projektdokumentation und verwenden Sie explorative Tests, um nach Dateneingangspunkten oder Übergabepunkten zwischen Systemen oder Software zu suchen\n • Versuchen Sie, einmal gefundene logisch ungültige Daten in die Anwendung/das System einzufügen\n\n Spezifische Testmethode\n • Führen Sie funktional gültige Front-End-GUI-Tests für die Anwendung durch, um sicherzustellen, dass nur „gültige“ Werte akzeptiert werden.\n • Beobachten Sie bei Verwendung eines abfangenden Proxys HTTP POST/GET und suchen Sie nach Stellen, an denen Variablen wie Kosten und Qualität übergeben werden. Suchen Sie insbesondere nach „Übergaben“ zwischen Anwendungen/Systemen, bei denen möglicherweise Manipulationspunkte injiziert werden.\n • Sobald Variablen gefunden wurden, beginnen Sie damit, das Feld mit logisch „ungültigen“ Daten abzufragen, wie z. B. Sozialversicherungsnummern oder eindeutige Kennungen, die nicht existieren oder die nicht zur Geschäftslogik passen.\n Dieser Test überprüft, ob der Server ordnungsgemäß funktioniert und keine logisch ungültigen Daten akzeptiert.",
|
||||
"002": "Das Fälschen von Anfragen ist eine Methode, mit der Angreifer die Front-End-GUI-Anwendung umgehen, um Informationen direkt für die Back-End-Verarbeitung zu übermitteln. Das Ziel des Angreifers besteht darin, HTTP-POST/GET-Anforderungen über einen abfangenden Proxy mit Datenwerten zu senden, die von der Geschäftslogik der Anwendung nicht unterstützt, geschützt oder erwartet werden.\n\n Schwachstellen im Zusammenhang mit der Fähigkeit, Anforderungen zu fälschen, sind für jede Anwendung einzigartig und unterscheiden sich von der Datenvalidierung der Geschäftslogik dadurch, dass der Schwerpunkt darauf liegt, den Geschäftslogik-Workflow zu unterbrechen.\n\n Die Anwendung muss intelligent genug sein und mit einer Geschäftslogik entworfen werden, die Angreifer daran hindert, Parameter vorherzusagen und zu manipulieren, um den Programm- oder Geschäftslogikfluss zu untergraben oder versteckte/undokumentierte Funktionen wie Debugging auszunutzen.\n\n Generische Testmethode\n • Überprüfen Sie die Projektdokumentation und verwenden Sie explorative Tests, um nach erratenden, vorhersagbaren oder verborgenen Funktionen von Feldern zu suchen.\n • Versuchen Sie, einmal gefundene logisch gültige Daten in die Anwendung/das System einzufügen, damit der Benutzer die Anwendung/das System gegen den normalen Arbeitsablauf der Geschäftslogik durchlaufen kann.\n\n Spezifische Testmethode 1\n • Beobachten Sie bei Verwendung eines abfangenden Proxys HTTP POST/GET und suchen Sie nach Hinweisen darauf, dass Werte in regelmäßigen Abständen inkrementiert werden oder leicht zu erraten sind.\n • Wenn sich herausstellt, dass ein Wert erraten werden kann, kann dieser Wert erraten werden\ngeändert und man kann unerwartete Sichtbarkeit erlangen.\n\n Spezifische Testmethode 2\n • Beobachten Sie bei Verwendung eines abfangenden Proxys HTTP POST/GET und suchen Sie nach Hinweisen auf versteckte Funktionen wie Debug, die ein- oder aktiviert werden können.\n • Wenn welche gefunden werden, versuchen Sie, diese Werte zu erraten und zu ändern, um eine andere Antwort oder ein anderes Verhalten der Anwendung zu erhalten.",
|
||||
"003": "Viele Anwendungen sind so konzipiert, dass sie je nach Situation des Benutzers unterschiedliche Felder anzeigen, indem einige Eingaben ausgeblendet bleiben.\nIn vielen Fällen ist es jedoch möglich, versteckte Feldwerte mithilfe eines Proxys an den Server zu senden. In diesen Fällen müssen die serverseitigen Steuerelemente intelligent genug sein, um relationale oder serverseitige Bearbeitungen durchzuführen, um sicherzustellen, dass die richtigen Daten auf der Grundlage der benutzer- und anwendungsspezifischen Geschäftslogik für den Server zugelassen werden.\n\n Darüber hinaus darf die Anwendung nicht von nicht bearbeitbaren Steuerelementen, Dropdown-Menüs oder verborgenen Feldern für die Verarbeitung der Geschäftslogik abhängen, da diese Felder nur im Kontext der Browser nicht bearbeitbar bleiben. Benutzer können ihre Werte möglicherweise mit Proxy-Editor-Tools bearbeiten und versuchen, die Geschäftslogik zu manipulieren.\n\nSchwachstellen bei der Integritätsprüfung der Geschäftslogik sind insofern einzigartig, als diese Missbrauchsfälle anwendungsspezifisch sind und wenn Benutzer in der Lage sind, Änderungen vorzunehmen, sollten sie nur in der Lage sein, bestimmte Artefakte zu bestimmten Zeiten gemäß der Geschäftsprozesslogik zu schreiben oder zu aktualisieren/bearbeiten.\nDie Anwendung muss intelligent genug sein, um auf relationale Bearbeitungen zu prüfen, und Benutzern nicht erlauben, Informationen direkt an den Server zu senden, die ungültig sind, vertrauenswürdig sind, weil sie von nicht bearbeitbaren Steuerelementen stammen oder der Benutzer nicht berechtigt ist, sie über das Front-End zu senden.\n\n Generische Testmethode\n • Überprüfen Sie die Projektdokumentation und führen Sie explorative Tests durch, um nach Teilen der Anwendung/des Systems (z. B. Eingabefelder, Datenbanken oder Protokolle) zu suchen, die Daten/Informationen verschieben, speichern oder verarbeiten.\n • Bestimmen Sie für jede identifizierte Komponente, welche Art von Daten/Informationen logisch akzeptabel ist und vor welchen Arten die Anwendung/das System schützen sollte. Überlegen Sie auch, wer gemäß der Geschäftslogik in jeder Komponente Daten/Informationen einfügen, aktualisieren und löschen darf.\n • Versuchen Sie, die Daten-/Informationswerte mit ungültigen Daten/Informationen in jede Komponente (d. h. Eingabe, Datenbank oder Protokoll) von Benutzern einzufügen, zu aktualisieren oder zu bearbeiten, die gemäß dem Geschäftslogik-Workflow nicht zulässig sein sollten. \n\n Spezifische Testmethode 1\n • Verwenden einer Proxy-Erfassung und von HTTP-Verkehr, die nach verborgenen Feldern suchen.\n • Wenn ein verborgenes Feld gefunden wird, sehen Sie, wie sich diese Felder mit der GUI-Anwendung vergleichen, und beginnen Sie, diesen Wert über den Proxy abzufragen, indem Sie verschiedene Datenwerte senden, um den Geschäftsprozess zu umgehen und Werte zu manipulieren, auf die Sie keinen Zugriff haben sollten.\n\n Spezifische Testmethode 2\n • Verwenden einer Proxy-Erfassung und von HTTP-Verkehr, um einen Ort zu suchen, an dem Informationen in Bereiche der Anwendung eingefügt werden können, die nicht bearbeitet werden können.\n • Wenn es gefunden wird, vergleichen Sie diese Felder mit der GUI-Anwendung und beginnen Sie, diesen Wert über den Proxy abzufragen, indem Sie verschiedene Datenwerte senden, um den Geschäftsprozess zu umgehen und Werte zu manipulieren, auf die Sie keinen Zugriff haben sollten.\n\n Spezifische Testmethode 3\n • Komponenten der Anwendung oder des Systems auflisten, die bearbeitet werden könnten, z. B. Protokolle oder Datenbanken.\n • Versuchen Sie für jede identifizierte Komponente, ihre Informationen zu lesen, zu bearbeiten oder zu entfernen. Beispielsweise sollten Protokolldateien identifiziert werden und Tester sollten versuchen, die gesammelten Daten/Informationen zu manipulieren.",
|
||||
"004": "Es ist möglich, dass Angreifer Informationen über eine Anwendung sammeln, indem sie die Zeit überwachen, die zum Ausführen einer Aufgabe oder zum Geben einer Antwort benötigt wird.\n Darüber hinaus können Angreifer möglicherweise entworfene Geschäftsprozessabläufe manipulieren und unterbrechen, indem sie einfach aktive Sitzungen offen halten und ihre Transaktionen nicht im „erwarteten“ Zeitrahmen übermitteln.\n\n Schwachstellen in der Prozesstiming-Logik sind insofern einzigartig, als diese manuellen Missbrauchsfälle unter Berücksichtigung des anwendungs-/systemspezifischen Ausführungs- und Transaktionstimings erstellt werden sollten.\nDas Verarbeitungstiming kann Informationen darüber geben/durchsickern lassen, was in den Hintergrundprozessen der Anwendung/des Systems getan wird. Wenn eine Anwendung es Benutzern ermöglicht, durch die Verarbeitung von Zeitvariationen zu erraten, was das nächste Ergebnis sein wird, können Benutzer sich entsprechend anpassen und das Verhalten ändern.\n\n So testen Sie #1 \n Überprüfen Sie die Projektdokumentation und verwenden Sie explorative Tests, um nach Anwendungs-/Systemfunktionen zu suchen, die sich mit der Zeit auswirken könnten. Beispielsweise die Ausführungszeit oder Aktionen, die Benutzern helfen, ein zukünftiges Ergebnis vorherzusagen, oder die es einem ermöglichen, einen Teil der Geschäftslogik oder des Workflows zu umgehen.\n Zum Beispiel Transaktionen nicht in einer erwarteten Zeit abschließen.\n\n So testen Sie #2 \n Entwickeln Sie Missbrauchsfälle und führen Sie sie aus, um sicherzustellen, dass Angreifer keinen Vorteil basierend auf einem beliebigen Timing erlangen können.",
|
||||
"005": "Viele der Probleme, die Anwendungen lösen, erfordern Begrenzungen der Häufigkeit, mit der eine Funktion verwendet oder eine Aktion ausgeführt werden kann. Anwendungen müssen „intelligent genug“ sein, um es dem Benutzer nicht zu erlauben, sein Limit für die Nutzung dieser Funktionen zu überschreiten, da der Benutzer in vielen Fällen bei jeder Verwendung der Funktion einen Vorteil erlangen kann, der berücksichtigt werden muss, um den Eigentümer angemessen zu entschädigen .\n\n Schwachstellen im Zusammenhang mit dem Testen der Funktionsgrenzen sind anwendungsspezifisch und es müssen Missbrauchsfälle erstellt werden, die darauf abzielen, Teile der Anwendung/Funktionen/oder Aktionen mehr als die zulässige Anzahl von Malen auszuführen.\nAngreifer können möglicherweise die Geschäftslogik umgehen und eine Funktion häufiger als „zulässig“ ausführen, indem sie die Anwendung zum persönlichen Vorteil ausnutzen.\n\n So testen Sie #1\n Überprüfen Sie die Projektdokumentation und verwenden Sie explorative Tests, um nach Funktionen oder Merkmalen in der Anwendung oder dem System zu suchen, die während des Geschäftslogik-Workflows nicht mehr als einmal oder eine bestimmte Anzahl von Malen ausgeführt werden sollten.\n\n So testen Sie #2\n Entwickeln Sie für jede der gefundenen Funktionen und Merkmale, die während des Geschäftslogik-Workflows nur einmal oder eine bestimmte Anzahl von Malen ausgeführt werden sollten, Missbrauchs-/Missbrauchsfälle, die es einem Benutzer ermöglichen können, mehr als die zulässige Anzahl von Malen auszuführen.\n Kann ein Benutzer zum Beispiel mehrmals durch die Seiten vor und zurück navigieren und eine Funktion ausführen, die nur einmal ausgeführt werden sollte, oder kann ein Benutzer Einkaufswagen laden und entladen, was zusätzliche Rabatte ermöglicht.",
|
||||
"006": "Workflow-Schwachstellen umfassen jede Art von Schwachstelle, die es dem Angreifer ermöglicht, eine Anwendung/ein System so zu missbrauchen, dass er den entworfenen/beabsichtigten Workflow umgehen (nicht befolgen) kann.\n\n „Ein Workflow besteht aus einer Abfolge verbundener Schritte, wobei jeder Schritt ohne Verzögerung oder Lücke folgt und endet, kurz bevor der nächste Schritt beginnen kann. Workflow kann als jede Abstraktion von echter Arbeit angesehen werden.“\n\n Die Geschäftslogik der Anwendung muss erfordern, dass der Benutzer bestimmte Schritte in der richtigen/bestimmten Reihenfolge ausführt, und wenn der Workflow ohne korrekten Abschluss beendet wird, werden alle Aktionen und hervorgebrachten Aktionen „zurückgesetzt“ oder abgebrochen.\n\n Generische Testmethode\n • Überprüfen Sie die Projektdokumentation und verwenden Sie explorative Tests, um nach Methoden zu suchen, um Schritte im Anwendungsprozess in einer anderen Reihenfolge als dem entworfenen/beabsichtigten Ablauf der Geschäftslogik zu überspringen oder fortzusetzen.\n • Entwickeln Sie für jede Methode einen Missbrauchsfall und versuchen Sie, eine Aktion zu umgehen oder auszuführen, die gemäß dem Geschäftslogik-Workflow „nicht akzeptabel“ ist.\n\n Testmethode 1\n • Starten Sie eine Transaktion, die die Anwendung hinter den Punkten durchläuft, die Gutschriften/Punkte auf dem Benutzerkonto auslöst.\n • Stornieren Sie die Transaktion oder reduzieren Sie das endgültige Angebot, sodass die Punktewerte verringert werden sollten, und überprüfen Sie das Punkte-/Credit-System, um sicherzustellen, dass die richtigen Punkte/Credits erfasst wurden.\n\n Testmethode 2\n • Auf einem Content-Management- oder Bulletin-Board-System gültige Anfangstexte oder -werte eingeben und speichern.\n • Versuchen Sie dann, Daten anzuhängen, zu bearbeiten und zu entfernen, die die vorhandenen Daten in einem ungültigen Zustand oder mit ungültigen Werten belassen würden, um sicherzustellen, dass der Benutzer nicht berechtigt ist, die falschen Informationen zu speichern.\n Bei einigen „ungültigen“ Daten oder Informationen kann es sich um bestimmte Wörter (Obszönitäten) oder bestimmte Themen (z. B. politische Themen) handeln.",
|
||||
"007": "Der Missbrauch und die ungültige Verwendung einer gültigen Funktionalität kann Angriffe identifizieren, die versuchen, die Webanwendung aufzulisten, Schwachstellen zu identifizieren und Schwachstellen auszunutzen. Es sollten Tests durchgeführt werden, um festzustellen, ob Abwehrmechanismen auf Anwendungsebene vorhanden sind, um die Anwendung zu schützen.\n\n Der Mangel an aktiver Abwehr ermöglicht es einem Angreifer, ohne Rückgriff nach Schwachstellen zu suchen. Der Eigentümer der Anwendung weiß daher nicht, dass seine Anwendung angegriffen wird.\n\n Dieser Test ist insofern ungewöhnlich, als das Ergebnis aus allen anderen Tests gezogen werden kann, die gegen die Webanwendung durchgeführt wurden.\n Beachten Sie bei der Durchführung aller anderen Tests Maßnahmen, die darauf hindeuten könnten, dass die Anwendung über einen integrierten Selbstschutz verfügt:\n • Geänderte Antworten\n • Blockierte Anfragen\n • Aktionen, die einen Benutzer abmelden oder sein Konto sperren\n\n Diese dürfen nur lokalisiert werden. Übliche lokalisierte (pro Funktion) Abwehrmaßnahmen sind:\n • Ablehnen von Eingaben, die bestimmte Zeichen enthalten\n • Vorübergehendes Sperren eines Kontos nach einer Reihe von Authentifizierungsfehlern\n\n Lokale Sicherheitskontrollen sind nicht ausreichend. Gegen allgemeinen Missbrauch wie z. B.:\n • Erzwungenes Browsen\n • Umgehen der Eingabeüberprüfung der Präsentationsschicht\n • Mehrfachzugriffskontrollfehler\n • Zusätzliche, doppelte oder fehlende Parameternamen\n • Mehrere Fehler bei der Eingabeüberprüfung oder Überprüfung der Geschäftslogik\n • Es werden strukturierte Daten (z. B. JSPN, XML) in einem ungültigen Format empfangen\n • Eklatante Cross-Site-Scripting- oder SQL-Injection-Payloads werden empfangen\n • Nutzung der Anwendung schneller als möglich\n • Änderung des kontinentalen Standorts eines Benutzers\n • Änderung des Benutzeragenten\n • Zugriff auf einen mehrstufigen Geschäftsprozess in der falschen Reihenfolge\n • Große Anzahl oder hohe Nutzungsrate anwendungsspezifischer Funktionalität\n\n Nicht alle oben genannten müssen von der Anwendung überwacht werden, aber es gibt ein Problem, wenn dies nicht der Fall ist. Wurde durch das Testen der Webanwendung durch Ausführen der oben genannten Aktionen eine Reaktion gegen den Tester vorgenommen?\n Ist dies nicht der Fall, sollte der Tester melden, dass die Anwendung offenbar keine anwendungsweite aktive Abwehr gegen Missbrauch zu haben scheint.",
|
||||
"008": "Die Geschäftsprozesse vieler Anwendungen ermöglichen das Hochladen und Bearbeiten von Daten, die über Dateien übermittelt werden.\n Das Risiko besteht darin, dass Angreifer, indem sie Benutzern erlauben, Dateien hochzuladen, einen unerwarteten Dateityp übermitteln, der ausgeführt werden und die Anwendung oder das System durch Angriffe beeinträchtigen könnte, die die Website verunstalten, Remote-Befehle ausführen, die Systemdateien durchsuchen, die lokale Ressourcen, greifen andere Server an oder nutzen die lokalen Schwachstellen aus, um nur einige zu nennen.\n\n Schwachstellen im Zusammenhang mit dem Hochladen unerwarteter Dateitypen sind insofern einzigartig, als der Upload eine Datei schnell zurückweisen sollte, wenn sie keine bestimmte Erweiterung hat. Außerdem unterscheidet sich dies vom Hochladen bösartiger Dateien darin, dass in den meisten Fällen eine falsche Datei die gespeicherten Daten schädigen kann.\n\n Generische Testmethode\n • Überprüfen Sie die Projektdokumentation und führen Sie einige explorative Tests durch, um nach Dateitypen zu suchen, die von der Anwendung/dem System „nicht unterstützt“ werden sollten.\n • Versuchen Sie, diese „nicht unterstützten“ Dateien hochzuladen, und vergewissern Sie sich, dass sie ordnungsgemäß abgelehnt werden.\n • Wenn mehrere Dateien gleichzeitig hochgeladen werden können, müssen Tests durchgeführt werden, um sicherzustellen, dass jede Datei ordnungsgemäß bewertet wird.\n\n Spezifische Testmethode\n • Studieren Sie die logischen Anforderungen der Anwendung\n • Bereiten Sie eine Bibliothek mit Dateien vor, die zum Hochladen „nicht genehmigt“ wurden und möglicherweise Dateien wie jsp-, exe- oder html-Dateien enthalten, die Skripte enthalten.\n • Navigieren Sie in der Anwendung zum Dateiübermittlungs- oder Upload-Mechanismus.\n • Reichen Sie die „nicht genehmigte“ Datei zum Hochladen ein und vergewissern Sie sich, dass sie ordnungsgemäß am Hochladen gehindert werden.",
|
||||
"009": "Die Geschäftsprozesse vieler Anwendungen ermöglichen das Hochladen von Daten/Informationen.\n Um das Risiko zu verringern, akzeptieren wir möglicherweise nur bestimmte Dateierweiterungen, aber Angreifer sind in der Lage, bösartigen Code in inaktive Dateitypen einzukapseln.\n\n Schwachstellen im Zusammenhang mit dem Hochladen bösartiger Dateien sind insofern einzigartig, als diese „bösartigen“ Dateien leicht zurückgewiesen werden können, indem eine Geschäftslogik integriert wird, die Dateien während des Hochladevorgangs scannt und die als bösartig wahrgenommenen zurückweist.\nDarüber hinaus unterscheidet sich dies vom Hochladen unerwarteter Dateien darin, dass der Dateityp zwar akzeptiert werden kann, die Datei aber dennoch für das System schädlich sein kann.\n\n Allgemeine Testmethode\n • Überprüfen Sie die Projektdokumentation und verwenden Sie explorative Tests, die die Anwendung/das System untersuchen, um festzustellen, was eine „bösartige“ Datei in Ihrer Umgebung darstellt.\n • Entwickeln oder erwerben Sie eine bekannte „bösartige“ Datei.\n • Versuchen Sie, die bösartige Datei in die Anwendung/das System hochzuladen, und vergewissern Sie sich, dass sie korrekt abgelehnt wird.\n • Wenn mehrere Dateien gleichzeitig hochgeladen werden können, müssen Tests durchgeführt werden, um sicherzustellen, dass jede Datei ordnungsgemäß bewertet wird.\n\n Spezifische Testmethode 1\n • Die Verwendung der Metasploit-Nutzlastgenerierungsfunktion generiert einen Shellcode als ausführbare Windows-Datei mit dem Metasploit-Befehl „msfpayload“.\n • Senden Sie die ausführbare Datei über die Upload-Funktion der Anwendung und prüfen Sie, ob sie akzeptiert oder ordnungsgemäß abgelehnt wird.\n\n Spezifische Testmethode 2\n • Entwickeln oder erstellen Sie eine Datei, die den Malware-Erkennungsprozess der Anwendung nicht bestehen sollte.\n (es gibt viele im Internet verfügbar wie ducklin.htm oder ducklin-html.htm)\n • Senden Sie die ausführbare Datei über die Upload-Funktion der Anwendung und prüfen Sie, ob sie akzeptiert oder ordnungsgemäß abgelehnt wird.\n\n Spezifische Testmethode 3\n • Richten Sie den abfangenden Proxy ein, um die „gültige“ Anfrage für eine akzeptierte Datei zu erfassen.\n • Senden Sie eine „ungültige“ Anfrage mit einer gültigen/akzeptablen Dateierweiterung durch und prüfen Sie, ob die Anfrage angenommen oder ordnungsgemäß abgelehnt wird."
|
||||
},
|
||||
"client": {
|
||||
"001": "DOM-based Cross-Site Scripting ist der De-facto-Name für XSS-Bugs, die das Ergebnis aktiver browserseitiger Inhalte auf einer Seite sind, typischerweise JavaScript, die Benutzereingaben erhalten und dann etwas Unsicheres damit machen, was zur Ausführung von eingeschleusten Codes führt .\n\nDas DOM oder Document Object Model ist das Strukturformat, das zur Darstellung von Dokumenten in einem Browser verwendet wird. Das DOM ermöglicht es dynamischen Skripten wie JavaScript, auf Komponenten des Dokuments wie ein Formularfeld oder ein Sitzungscookie zu verweisen.\n Eine DOM-basierte XSS-Schwachstelle kann auftreten, wenn aktiver Inhalt, z. B. eine JavaScript-Funktion, durch eine speziell gestaltete Anforderung so geändert wird, dass ein DOM-Element von einem Angreifer gesteuert werden kann.\n\n Nicht alle XSS-Fehler erfordern, dass der Angreifer den vom Server zurückgegebenen Inhalt kontrolliert, sondern können stattdessen schlechte JavaScript-Codierungspraktiken missbrauchen. Im Vergleich zu anderen Cross-Site-Scripting-Schwachstellen, bei denen ein nicht bereinigter Parameter vom Server übergeben, an den Benutzer zurückgegeben und im Kontext des Browsers des Benutzers ausgeführt wird, steuert eine DOM-basierte XSS-Schwachstelle den Fluss des Codes mithilfe von Elementen der Document Object Model (DOM) zusammen mit Code, der vom Angreifer erstellt wurde, um den Fluss zu ändern.\n Aufgrund ihrer Natur können DOM-basierte XSS-Schwachstellen in vielen Fällen ausgeführt werden, ohne dass der Server feststellen kann, was tatsächlich ausgeführt wird.\n\n Ein Angreifer kann #<script>alert(‘xss’)</script> an die betroffene Seiten-URL anhängen, was bei Ausführung das Warnfeld anzeigen würde. In diesem Fall würde der angehängte Code nicht an den Server gesendet, da alles nach dem #-Zeichen vom Browser nicht als Teil der Abfrage, sondern als Fragment behandelt wird.\n\n Testen auf DOM-basierte XSS-Schwachstellen:\n Blackbox-Tests für DOM-basiertes XSS werden normalerweise nicht durchgeführt, da der Zugriff auf den Quellcode immer verfügbar ist, da er zur Ausführung an den Client gesendet werden muss.\n Viele Websites verlassen sich auf große Funktionsbibliotheken, die sich oft über Hunderttausende von Codezeilen erstrecken und nicht selbst entwickelt wurden. In diesen Fällen wird das Top-Down-Testen oft zur einzig wirklich praktikablen Option.\n Dasselbe gilt auch für Top-Down-Tests, wenn die Eingaben oder deren Fehlen nicht von vornherein identifiziert werden. Benutzereingaben erfolgen in zwei Hauptformen:\n • Eingaben, die vom Server auf eine Weise auf die Seite geschrieben werden, die kein direktes XSS zulässt\n • Von clientseitigen JavaScript-Objekten erhaltene Eingaben\n\n Automatisiertes Testen hat nur sehr begrenzten Erfolg beim Identifizieren und Validieren von DOM-basiertem XSS, da es XSS normalerweise identifiziert, indem es eine bestimmte Nutzlast sendet und versucht, es in der Serverantwort zu beobachten.\n Daher sollten manuelle Tests durchgeführt werden, die durch Untersuchen von Bereichen im Code durchgeführt werden können, in denen auf Parameter verwiesen wird, die für einen Angreifer nützlich sein können.",
|
||||
"002": "Eine JavaScript-Injection-Schwachstelle ist eine Unterart von Cross Site Scripting (XSS), bei der beliebiger JavaScript-Code injiziert werden kann, der von der Anwendung im Browser des Opfers ausgeführt wird.\n Diese Sicherheitsanfälligkeit kann viele Konsequenzen haben, wie die Offenlegung von Sitzungscookies eines Benutzers, die verwendet werden könnten, um sich als das Opfer auszugeben, oder allgemeiner kann es dem Angreifer ermöglichen, den von den Opfern gesehenen Seiteninhalt oder das Anwendungsverhalten zu ändern.\n\n Eine solche Schwachstelle tritt auf, wenn der Anwendung eine ordnungsgemäße vom Benutzer bereitgestellte Eingabe- und Ausgabevalidierung fehlt. JavaScript wird verwendet, um Webseiten dynamisch zu füllen, diese Injektion erfolgt während dieser Inhaltsverarbeitungsphase und wirkt sich folglich auf das Opfer aus.\n Wenn Sie versuchen, diese Art von Problemen auszunutzen, bedenken Sie, dass einige Zeichen von verschiedenen Browsern unterschiedlich behandelt werden.",
|
||||
"003": "HTML-Injektion ist eine Art von Injektionsproblem, das auftritt, wenn a\nDer Benutzer kann einen Eingabepunkt steuern und beliebigen HTML-Code in eine anfällige Webseite einfügen.\nDiese Schwachstelle kann viele Konsequenzen haben, wie z. B. die Offenlegung\nvon Sitzungscookies eines Benutzers, die verwendet werden könnten, um sich als das auszugeben\nOpfer, oder allgemeiner kann es dem Angreifer ermöglichen, die zu ändern\nSeiteninhalte, die von den Opfern gesehen wurden.\n\n Diese Sicherheitsanfälligkeit tritt auf, wenn die Benutzereingabe nicht ordnungsgemäß bereinigt und die Ausgabe nicht codiert ist. Eine Injektion ermöglicht es dem Angreifer, eine bösartige HTML-Seite an ein Opfer zu senden. Der angegriffene Browser ist nicht in der Lage, die legitimen von den bösartigen Teilen zu unterscheiden (zu vertrauen) und wird folglich alle im Opferkontext als legitim analysieren und ausführen.\n\n Es gibt eine breite Palette von Methoden und Attributen, die zum Rendern von HTML-Inhalten verwendet werden können. Wenn diese Methoden mit einer nicht vertrauenswürdigen Eingabe versehen sind, besteht ein hohes XSS-Risiko.\n Bösartiger HTML-Code könnte beispielsweise über innerHTML eingeschleust werden, das verwendet wird, um vom Benutzer eingefügten HTML-Code wiederzugeben. Eine unsachgemäße Verwendung dieser Eigenschaft bedeutet mangelnde Bereinigung durch nicht vertrauenswürdige Eingaben und fehlende Ausgabecodierung.\n Wenn Zeichenfolgen nicht korrekt bereinigt werden, kann das Problem zu einer XSS-basierten HTML-Injektion führen.\n Eine andere Methode könnte document.write() sein.\n\nWenn Sie versuchen, diese Art von Problemen auszunutzen, bedenken Sie, dass einige Zeichen von verschiedenen Browsern unterschiedlich behandelt werden.",
|
||||
"004": "Die clientseitige URL-Umleitung, auch bekannt als offene Umleitung, ist ein Eingabevalidierungsfehler, der auftritt, wenn eine Anwendung eine benutzergesteuerte Eingabe akzeptiert, die einen Link angibt, der zu einer externen URL führt, die bösartig sein könnte.\nDiese Art von Schwachstelle könnte verwendet werden, um einen Phishing-Angriff durchzuführen oder ein Opfer auf eine infizierte Seite umzuleiten.\n\nDiese Schwachstelle tritt auf, wenn eine Anwendung nicht vertrauenswürdige Eingaben akzeptiert, die einen URL-Wert enthalten, ohne sie zu bereinigen. Dieser URL-Wert könnte dazu führen, dass die Webanwendung den Benutzer auf eine andere Seite umleitet, beispielsweise eine bösartige Seite, die vom Angreifer kontrolliert wird.\n\n Durch das Ändern einer nicht vertrauenswürdigen URL-Eingabe zu einer bösartigen Website kann ein Angreifer erfolgreich einen Phishing-Betrug starten und Benutzeranmeldeinformationen stehlen.\n Darüber hinaus könnten offene Umleitungen auch verwendet werden, um böswillig eine URL zu erstellen, die die Zugriffskontrollprüfungen der Anwendung umgeht und den Angreifer dann zu privilegierten Funktionen weiterleitet, auf die er normalerweise keinen Zugriff hätte.\n\n Testen auf Sicherheitslücken bei der Client-seitigen URL-Umleitung:\nWenn Tester manuell nach dieser Art von Schwachstelle suchen müssen, müssen sie feststellen, ob clientseitige Umleitungen im clientseitigen Code implementiert sind.\n Diese Umleitungen könnten beispielsweise in JavaScript über das Objekt „window.location“ implementiert werden, mit dem der Browser durch einfaches Zuweisen eines Strings auf eine andere Seite geleitet werden kann. Wenn das Skript keine Validierung der Variablen „redir“ durchführt, wird diese nicht validierte Eingabe an das windows.location-Objekt weitergeleitet, wodurch eine URL-Umleitungs-Schwachstelle entsteht.",
|
||||
"005": "Eine CSS-Injection-Schwachstelle beinhaltet die Möglichkeit, beliebigen CSS-Code im Kontext einer vertrauenswürdigen Website einzufügen, und dieser wird im Browser des Opfers gerendert.\nDie Auswirkungen einer solchen Schwachstelle können je nach bereitgestellter CSS-Payload variieren: Sie könnte unter Umständen zu Cross-Site Scripting, zu Datenexfiltration im Sinne des Extrahierens sensibler Daten oder zu UI-Modifikationen führen.\n\n Eine solche Schwachstelle tritt auf, wenn die Anwendung die Bereitstellung von benutzergeneriertem CSS zulässt oder es möglich ist, irgendwie in die legitimen Stylesheets einzugreifen.\n Das Einfügen von Code in den CSS-Kontext gibt dem Angreifer die Möglichkeit, JavaScript unter bestimmten Bedingungen auszuführen sowie sensible Werte durch CSS-Selektoren und Funktionen zu extrahieren, die HTTP-Anforderungen generieren können.\n\n Insbesondere könnte der Angreifer das Opfer angreifen, indem er es auffordert, die folgenden URLs zu besuchen:\n • www.victim.com/#red;-o-link:’javascript:alert(1)’;-o-linksource:current; (Oper [8,12])\n • www.victim.com/#red;-:expression(alert(URL=1)); (IE 7/8)\n\n Viel interessantere Angriffsszenarien beinhalten die Möglichkeit, Daten durch die Übernahme reiner CSS-Regeln zu extrahieren.\nSolche Angriffe können über CSS-Selektoren durchgeführt werden und zum Beispiel dazu führen, Anti-CSRF-Token zu stehlen.\n\n Testen auf CSS-Injection-Schwachstellen:\n Es müssen manuelle Tests durchgeführt und der JavaScript-Code analysiert werden, um zu verstehen, ob die Angreifer eigene Inhalte im CSS-Kontext einfügen können. Insbesondere sollte uns interessieren, wie die Website CSS-Regeln auf Basis der Eingaben zurückgibt.",
|
||||
"006": "Eine ClientSide Resource Manipulation-Schwachstelle ist ein Fehler bei der Eingabevalidierung, der auftritt, wenn eine Anwendung eine benutzergesteuerte Eingabe akzeptiert, die den Pfad einer Ressource angibt (d. h. die Quelle eines Iframes, js, Applets).\nEine solche Schwachstelle besteht insbesondere in der Möglichkeit, die URLs zu kontrollieren, die auf einige auf einer Webseite vorhandene Ressourcen verweisen.\n Die Auswirkungen können je nach Art des Elements variieren, dessen URL vom Angreifer kontrolliert wird, und es wird normalerweise verwendet, um Cross-Site-Scripting-Angriffe durchzuführen.\n\n Eine solche Schwachstelle tritt auf, wenn die Anwendung Benutzer verwendet\nkontrollierte URLs zum Verweisen auf externe/interne Ressourcen.\n Unter diesen Umständen ist es möglich, das Verhalten der erwarteten Anwendung zu beeinträchtigen, indem schädliche Objekte geladen und wiedergegeben werden.\n\n Testen auf Sicherheitslücken in Bezug auf clientseitige Ressourcenmanipulation:\nUm manuell nach dieser Art von Schwachstelle zu suchen, müssen wir feststellen, ob die Anwendung Eingaben verwendet, ohne sie korrekt zu validieren. Diese stehen unter der Kontrolle des Benutzers, der möglicherweise die URL einiger Ressourcen angeben kann.\n Da es viele Ressourcen gibt, die in die Anwendung aufgenommen werden könnten, sollten clientseitige Skripts, die die zugehörigen URLs verarbeiten, auf mögliche Probleme untersucht werden. \n\n Nachfolgend sind die möglichen Injektionsstellen (Sink) aufgeführt, die überprüft werden sollten: \n • Ressource: Frame \n • Tag/Methode: iframe \n • Sink: src \n\n • Ressource: Link \n • Tag/Methode: a \n • Sink: href\n\n • Ressource: AJAX Request \n • Tag/Methode: xhr.open(method, [url], true); \n • Sink: URL href\n\n • Ressource: CSS \n • Tag/Methode: link \n\n • Ressource: Image \n • Tag/Methode: img \n\n • Ressource: Object \n • Tag/Methode: object \n • Sink: src\n\n • Ressource: Script \n • Tag/Methode: script \n • Sink: data src",
|
||||
"007": "Cross Origin Resource Sharing oder CORS ist ein Mechanismus, der es einem Webbrowser ermöglicht, „domänenübergreifende“ Anforderungen mithilfe der XMLHttpRequest L2-API auf kontrollierte Weise auszuführen.\n In der Vergangenheit erlaubte die XMLHttpRequest L1-API nur das Senden von Anforderungen innerhalb desselben Ursprungs, da sie durch dieselbe Ursprungsrichtlinie eingeschränkt war.\n\n Cross-Origin-Anfragen haben einen Origin-Header, der die Domäne identifiziert, die die Anfrage initiiert, und immer an den Server gesendet wird. CORS definiert das Protokoll, das zwischen einem Webbrowser und einem Server verwendet werden soll, um festzustellen, ob eine Cross-Origin-Anforderung zulässig ist.\n Um dieses Ziel zu erreichen, sind an diesem Prozess einige HTTP-Header beteiligt, die von allen gängigen Browsern unterstützt werden, darunter:\n • Origin \n • Access-Control-Request-Method \n • Access-Control-Request-Headers \n • Access-Control-Allow-Origin \n • Access-Control-Allow-Credentials \n • Access-Control-Allow-Methods \n • Access-Control-Allow-Headers\n\n Die CORS-Spezifikation schreibt vor, dass für nicht einfache Anforderungen, wie z. B. andere Anforderungen als GET oder POST oder Anforderungen, die Anmeldeinformationen verwenden, im Voraus eine OPTIONS-Anforderung vor dem Flug gesendet werden muss, um zu prüfen, ob sich der Anforderungstyp negativ auf die Daten auswirkt .\n Die Preflight-Anforderung prüft die vom Server zugelassenen Methoden und Header, und wenn Anmeldeinformationen zulässig sind, entscheidet der Browser basierend auf dem Ergebnis der OPTIONS-Anforderung, ob die Anforderung zugelassen wird oder nicht.\n\n Überprüfen Sie die HTTP-Header, um zu verstehen, wie CORS verwendet wird, insbesondere sollten wir uns sehr für den Origin-Header interessieren, um zu erfahren, welche Domänen zulässig sind.\n Außerdem ist eine manuelle Überprüfung des JavaScripts erforderlich, um festzustellen, ob der Code aufgrund einer unsachgemäßen Handhabung von Benutzereingaben anfällig für Code-Injection ist.",
|
||||
"008": "ActionScript ist die auf ECMAScript basierende Sprache, die von Flash-Anwendungen verwendet wird, wenn es um interaktive Anforderungen geht.\n Dort sind drei\nVersionen der ActionScript-Sprache. ActionScript 1.0 und ActionScript 2.0 sind sich sehr ähnlich, wobei ActionScript 2.0 eine Erweiterung von ActionScript 1.0 ist. ActionScript 3.0, eingeführt mit Flash Player 9, ist eine Neufassung der Sprache, um objektorientiertes Design zu unterstützen.\n\n ActionScript hat wie jede andere Sprache einige Implementierungsmuster, die zu Sicherheitsproblemen führen können.\n Da Flash-Anwendungen oft in Browser eingebettet sind, können Schwachstellen wie DOM-basiertes Cross-Site Scripting (XSS) in fehlerhaften Flash-Anwendungen vorhanden sein.\n\n Dekompilierung\n Da SWF-Dateien von einer im Player selbst eingebetteten virtuellen Maschine interpretiert werden, können sie möglicherweise dekompiliert und analysiert werden. Der bekannteste und kostenlosste ActionScript 2.0-Decompiler ist Flare.\n Die Dekompilierung hilft Testern, da sie ein quellcodegestütztes oder White-Box-Testen der Flash-Anwendungen ermöglicht. Das kostenlose Tool SWFScan von HP kann sowohl ActionScript 2.0 als auch ActionScript 3.0 dekompilieren.\n\n Angriffe und Flash-Player-Version Seit Mai 2007 wurden drei neue Versionen des Flash-Players von Adobe veröffentlicht. Jede neue Version schränkt einige der Angriffe ein.\n\n Player-Version: v9.0 r47/48\n • asfunction: Ja\n • Externe Schnittstelle: Ja\n • GetURL: Ja\n • HTML-Injektion: Ja\n\n Player-Version: v9.0 r115\n • asfunction: Nein\n • Externe Schnittstelle: Ja\n • GetURL: Ja\n • HTML-Injektion: Ja\n\n Player-Version: v9.0 r124\n • asfunction: Nein\n • Externe Schnittstelle: Ja\n • GetURL: Ja\n • HTML-Injection: Teilweise",
|
||||
"009": "„Clickjacking“ (das eine Teilmenge des „UI-Redressing“ ist) ist eine bösartige Technik, die darin besteht, einen Webbenutzer dazu zu verleiten, mit etwas zu interagieren, das anders ist als das, womit der Benutzer glaubt, dass er interagiert.\n Diese Art von Angriff, der allein oder in Kombination mit anderen Angriffen verwendet werden kann, könnte möglicherweise nicht autorisierte Befehle senden oder vertrauliche Informationen preisgeben, während das Opfer auf scheinbar harmlosen Webseiten interagiert.\n\n Ein Clickjacking-Angriff verwendet scheinbar harmlose Funktionen von HTML und Javascript, um das Opfer zu unerwünschten Aktionen zu zwingen, wie z. B. das Klicken auf eine Schaltfläche, die scheinbar eine andere Operation ausführt.\n\n Um diese Art von Technik auszuführen, muss der Angreifer eine scheinbar harmlose Webseite erstellen, die die Zielanwendung durch die Verwendung eines Iframes lädt.\n Sobald dies geschehen ist, könnte der Angreifer das Opfer dazu bringen, mit seiner fiktiven Webseite zu interagieren.\nSobald das Opfer auf der fiktiven Webseite surft, denkt es, dass es mit der sichtbaren Benutzeroberfläche interagiert, tatsächlich führt es jedoch Aktionen auf der versteckten Seite aus.\n\nDiese Art von Angriff ist häufig darauf ausgelegt, einer angreifenden Website zu ermöglichen, Benutzeraktionen auf der Ziel-Website zu veranlassen, selbst wenn Anti-CSRF-Token verwendet werden. . Daher ist es wichtig, wie beim CSRF-Angriff, Webseiten der Zielseite so zu kennzeichnen, dass sie Eingaben des Benutzers entgegennehmen.\n\nWir müssen herausfinden, ob die Website, die wir testen, keinen Schutz vor Clickjacking-Angriffen hat oder, ob die Entwickler Schutzmaßnahmen implementiert haben, ob diese Techniken umgangen werden können.\nMethoden zum Schutz einer Webseite vor Clickjacking können in zwei Makrokategorien unterteilt werden:\n • Clientseitiger Schutz: Frame Busting\n • Serverseitiger Schutz: X-Frame-Optionen\n\n Einige Frame-Busting-Techniken versuchen, Frames zu unterbrechen, indem sie dem Attribut „parent.location“ in der „counter-action“-Anweisung einen Wert zuweisen. Solche Aktionen sind zum Beispiel:\n • self.parent.location = document.location\n • parent.location.href = self.location\n • parent.location = self.location",
|
||||
"010": "Traditionell erlaubt das HTTP-Protokoll nur eine Anfrage/Antwort pro TCP-Verbindung. Asynchronous JavaScript and XML (AJAX) ermöglicht es Clients, Daten asynchron an den Server zu senden und zu empfangen, AJAX erfordert jedoch, dass der Client die Anforderungen initiiert und auf die Serverantworten wartet (Halbduplex).\n\n HTML5-WebSockets ermöglichen es dem Client/Server, „Vollduplex“-Kommunikationskanäle (zwei Wege) zu erstellen, sodass Client und Server wirklich asynchron kommunizieren können. WebSockets führen ihren anfänglichen „Upgrade“-Handshake über HTTP durch und von da an wird die gesamte Kommunikation über TCP-Kanäle unter Verwendung von Frames ausgeführt.\n\n 1: Identifizieren Sie, dass die Anwendung WebSockets verwendet\n • Untersuchen Sie den clientseitigen Quellcode auf das URI-Schema ws:// oder wss://\n • Verwenden Sie Browser Developer Tools, um die Netzwerk-WebSocket-Kommunikation anzuzeigen\n • Verwenden Sie die WebSocket-Registerkarte von OWASP Zed Attack Proxy (ZAP).\n\n 2: Ursprung\n • Versuchen Sie mithilfe eines WebSocket-Clients, eine Verbindung zum Remote-WebSocket-Server herzustellen\n • Wenn eine Verbindung hergestellt wird, überprüft der Server möglicherweise nicht den Ursprungsheader des WebSocket-Handshakes\n\n 3: Vertraulichkeit und Integrität\n • Überprüfen Sie, ob die WebSocket-Verbindung SSL verwendet, um vertrauliche Informationen zu übertragen (wss://)\n • Überprüfen Sie die SSL-Implementierung auf Sicherheitsprobleme (gültiges Zertifikat, BEAST, CRIME, RC4 usw.).\n\n 4: Authentifizierung\n • WebSockets führen keine Authentifizierung durch, es sollten normale Blackbox-Authentifizierungstests durchgeführt werden\n\n 5: Autorisierung\n • WebSockets behandeln keine Autorisierung, es sollten normale Blackbox-Autorisierungstests durchgeführt werden\n\n 6: Eingangsbereinigung\n • Verwenden Sie die WebSocket-Registerkarte von OWASP Zed Attack Proxy (ZAP), um WebSocket-Anforderungen und -Antworten wiederzugeben und zu fuzzen",
|
||||
"011": "Web Messaging (auch bekannt als Cross Document Messaging) ermöglicht Anwendungen, die auf verschiedenen Domänen ausgeführt werden, auf sichere Weise zu kommunizieren.\n Diese Einschränkung im Browser dient dazu, eine böswillige Website daran zu hindern, vertrauliche Daten von anderen iFrames, Registerkarten usw. zu lesen. Es gibt jedoch einige legitime Fälle, in denen zwei vertrauenswürdige Websites Daten untereinander austauschen müssen. Um diesem Bedarf gerecht zu werden, wurde Cross Document Messaging innerhalb der WHATWG-HTML5-Entwurfsspezifikation eingeführt und in allen gängigen Browsern implementiert.\n Es ermöglicht eine sichere Kommunikation zwischen mehreren Ursprüngen über iFrames, Registerkarten und Fenster hinweg.\n\n Die Messaging-API führte die Methode postMessage() ein, mit der Klartext-Nachrichten ursprungsübergreifend versendet werden können. Es besteht aus zwei Parametern, Nachricht und Domäne.\n\n Es gibt einige Sicherheitsbedenken bei der Verwendung von „*“ als Domain, die wir unten besprechen. Um dann Nachrichten zu empfangen, muss die empfangende Website einen neuen Event-Handler hinzufügen und hat die folgenden Attribute:\n • data: Der Inhalt der eingehenden Nachricht\n • Herkunft: Die Herkunft des Absenderdokuments\n • Quelle: Quellfenster\n\nEs müssen manuelle Tests durchgeführt und der JavaScript-Code analysiert werden, um herauszufinden, wie Web Messaging implementiert ist.\nInsbesondere sollte uns interessieren, wie die Website Nachrichten von nicht vertrauenswürdigen Domänen einschränkt und wie die Daten selbst für vertrauenswürdige Domänen gehandhabt werden.",
|
||||
"012": "Lokaler Speicher, auch als Webspeicher oder Offlinespeicher bekannt, ist ein Mechanismus zum Speichern von Daten als Schlüssel/Wert-Paare, die an eine Domäne gebunden sind und durch dieselbe Ursprungsrichtlinie (SOP) erzwungen werden.\n Es gibt zwei Objekte, localStorage, das persistent ist und Neustarts des Browsers/Systems überstehen soll, und sessionStorage, das temporär ist und nur existiert, bis das Fenster oder die Registerkarte geschlossen wird.\n Im Durchschnitt erlauben Browser in diesem Speicher etwa 5 MB pro Domain zu speichern, was im Vergleich zu den 4 KB Cookies ein großer Unterschied ist, aber der Hauptunterschied aus Sicherheitsperspektive besteht darin, dass die in diesen beiden Objekten gespeicherten Daten im Client und niemals gespeichert werden an den Server gesendet.\n\n Zunächst müssen wir prüfen, ob der Local Storage verwendet wird. Dies kann überprüft werden, wenn Sie das Browser-Tool verwenden, und dann unter Ressourcen zu „Lokaler Speicher“ und „Webspeicher“ gehen.\n\n Als nächstes müssen manuelle Tests durchgeführt werden, um festzustellen, ob die Website sensible Daten im Speicher speichert, die ein Risiko darstellen und die Auswirkungen eines Informationslecks dramatisch erhöhen werden.\n Überprüfen Sie auch den Code, der den Speicher verarbeitet, um festzustellen, ob er anfällig für Injektionsangriffe ist, ein häufiges Problem, wenn der Code der Eingabe oder Ausgabe nicht entkommt.",
|
||||
"013": "Die XSSI-Schwachstelle (Cross Site Script Inclusion) ermöglicht den Verlust vertraulicher Daten über Ursprungs- oder Domänengrenzen hinweg. Zu den sensiblen Daten können authentifizierungsbezogene Daten (Anmeldestatus, Cookies, Authentifizierungstoken, Sitzungs-IDs usw.) oder persönliche oder sensible personenbezogene Daten des Benutzers (E-Mail-Adressen, Telefonnummern, Kreditkartendaten, Sozialversicherungsnummern usw.) gehören. XSSI ist ein clientseitiger Angriff, der Cross Site Request Forgery (CSRF) ähnelt, jedoch einen anderen Zweck verfolgt.\n\nWährend CSRF den authentifizierten Benutzerkontext verwendet, um bestimmte zustandsverändernde Aktionen innerhalb der Seite eines Opfers auszuführen (z. B. Geld auf das Konto des Angreifers überweisen, Berechtigungen ändern, Passwort zurücksetzen usw.), verwendet XSSI stattdessen JavaScript auf der Clientseite, um vertrauliche Daten preiszugeben aus authentifizierten Sitzungen.\n\nTestziele\n• Lokalisieren Sie vertrauliche Daten im gesamten System.\n• Bewerten Sie den Verlust sensibler Daten mithilfe verschiedener Techniken.\n\nSo testen Sie\n• Sammeln Sie Daten mithilfe authentifizierter und nicht authentifizierter Benutzersitzungen\n• Stellen Sie fest, ob die sensiblen Daten mithilfe von JavaScript verloren gehen können\n• Überprüfen Sie, ob über globale Variablen vertrauliche Daten verloren gehen\n• Überprüfen Sie mithilfe globaler Funktionsparameter, ob vertrauliche Daten verloren gehen\n• Suchen Sie nach Lecks sensibler Daten durch JavaScript-Laufzeitfehler\n• Prüfen Sie mithilfe von „this“ auf sensible Datenlecks durch Prototypenverkettung."
|
||||
},
|
||||
"api": {
|
||||
"001": "GraphQL ist in modernen APIs sehr beliebt geworden. Es bietet Einfachheit und verschachtelte Objekte, die eine schnellere Entwicklung ermöglichen. Obwohl jede Technologie Vorteile bietet, kann sie die Anwendung auch neuen Angriffsflächen aussetzen. Der Zweck dieses Szenarios besteht darin, einige häufige Fehlkonfigurationen und Angriffsvektoren für Anwendungen bereitzustellen, die GraphQL verwenden.\n\nTestziele:\n• Beurteilen Sie, dass eine sichere und produktionsbereite Konfiguration bereitgestellt wird.\n• Beurteilen Sie, dass eine sichere und produktionsbereite Konfiguration bereitgestellt wird.\n• Stellen Sie sicher, dass ordnungsgemäße Zugangskontrollen angewendet werden.\n\nDas Testen von GraphQL-Knoten unterscheidet sich nicht wesentlich vom Testen anderer API-Technologien.\nIntrospektionsabfragen sind die Methode, mit der GraphQL Sie fragen lässt, welche Abfragen unterstützt werden, welche Datentypen verfügbar sind und viele weitere Details, die Sie benötigen, wenn Sie sich einem Test einer GraphQL-Bereitstellung nähern.\nEin Tool wie GraphQL Voyager kann verwendet werden, um ein besseres Verständnis des GraphQL-Endpunkts zu erhalten. Dieses Tool erstellt eine ERD-Darstellung (Entity Relationship Diagram) des GraphQL-Schemas, sodass Sie einen besseren Einblick in die beweglichen Teile des Systems erhalten, das Sie testen.\n\nDie Introspektion ist der erste Ort, um nach Autorisierungsproblemen zu suchen. Wie bereits erwähnt, sollte der Zugang zur Introspektion eingeschränkt werden, da sie die Datenextraktion und Datenerfassung ermöglicht. Sobald ein Tester Zugriff auf das Schema und Kenntnisse über die zu extrahierenden vertraulichen Informationen hat, sollte er Abfragen senden, die nicht aufgrund unzureichender Berechtigungen blockiert werden. GraphQL erzwingt standardmäßig keine Berechtigungen, daher liegt es an der Anwendung, die Autorisierungsdurchsetzung durchzuführen.\nDas Testen der Autorisierungsimplementierung variiert von Bereitstellung zu Bereitstellung, da jedes Schema unterschiedliche vertrauliche Informationen und daher unterschiedliche Ziele aufweist, auf die es sich konzentrieren muss.\n\nGraphQL ist die Implementierung der API-Schicht einer Anwendung und leitet als solche die Anforderungen normalerweise direkt an eine Back-End-API oder die Datenbank weiter. Dadurch können Sie jede zugrunde liegende Schwachstelle wie SQL-Injection, Command-Injection, Cross-Site-Scripting usw. ausnutzen. Die Verwendung von GraphQL ändert lediglich den Eintrittspunkt der bösartigen Nutzlast.\n\nGraphQL kann zur Laufzeit auf unerwartete Fehler stoßen. Wenn ein solcher Fehler auftritt, sendet der Server möglicherweise eine Fehlerantwort, die interne Fehlerdetails oder Anwendungskonfigurationen oder -daten offenlegen kann. Dadurch kann ein böswilliger Benutzer an weitere Informationen über die Anwendung gelangen. Im Rahmen des Tests sollten Fehlermeldungen durch das Senden unerwarteter Daten überprüft werden, ein Vorgang, der als Fuzzing bezeichnet wird. Die Antworten sollten nach potenziell sensiblen Informationen durchsucht werden, die mit dieser Technik offengelegt werden könnten."
|
||||
},
|
||||
"no_info": "Kein Informationen für die gegebene Referenznummer gefunden."
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,40 @@
|
|||
{
|
||||
"global": {
|
||||
"actions": "Actions",
|
||||
"action.profile": "Profile",
|
||||
"action.login": "Login",
|
||||
"action.logout": "Logout",
|
||||
"action.retry": "Try again",
|
||||
"action.info": "Info",
|
||||
"action.confirm": "Confirm",
|
||||
"action.save": "Save",
|
||||
"action.cancel": "Cancel",
|
||||
"action.return": "Return",
|
||||
"action.exit": "Exit",
|
||||
"action.update": "Update",
|
||||
"action.edit": "Edit",
|
||||
"action.export": "Export",
|
||||
"action.download": "Download",
|
||||
"action.report": "Report",
|
||||
"action.reset": "Reset",
|
||||
"action.complete": "Complete",
|
||||
"action.disable": "Deactivate",
|
||||
"action.enable": "Activate",
|
||||
"action.close": "Close",
|
||||
"action.yes": "Yes",
|
||||
"action.no": "No",
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
"password": "Password",
|
||||
"no.progress": "No progress",
|
||||
"project": "Project",
|
||||
"version": "Version",
|
||||
"validationMessage": {
|
||||
"inputNotMatching": "Input does not match!"
|
||||
},
|
||||
"retry.dialog": {
|
||||
"title": "Something went wrong...",
|
||||
"information": "An error occured while processing your request. \nPlease retry or try it again later."
|
||||
}
|
||||
},
|
||||
"languageKeys":{
|
||||
"de-DE": "German",
|
||||
|
@ -35,18 +58,105 @@
|
|||
"failed": "Wrong username or password",
|
||||
"unauthorized": "User not found. Please register and try again"
|
||||
},
|
||||
"profile": {
|
||||
"header": "Userprofile",
|
||||
"username": {
|
||||
"title": "Username",
|
||||
"placeholder": "Username"
|
||||
},
|
||||
"firstName": {
|
||||
"title": "Firstname",
|
||||
"placeholder": "Firstname"
|
||||
},
|
||||
"lastName": {
|
||||
"title": "Lastname",
|
||||
"placeholder": "Lastname"
|
||||
},
|
||||
"eMail": {
|
||||
"title": "E-Mail",
|
||||
"placeholder": "No E-Mail verified."
|
||||
},
|
||||
"validationMessage": {
|
||||
"firstNameRequired": "Firstname is required.",
|
||||
"lastNameRequired": "Lastname is required."
|
||||
},
|
||||
"languageLabel": "Change language:",
|
||||
"password": {
|
||||
"title": "Change password:",
|
||||
"button" : "Change password",
|
||||
"old": "Old password",
|
||||
"new": "New password",
|
||||
"confirmNew": "Confirm new password",
|
||||
"validationMessage": {
|
||||
"passwordRequired": "Password is required."
|
||||
}
|
||||
}
|
||||
},
|
||||
"tutorial": {
|
||||
"header": "Getting started with C4PO",
|
||||
"carousel": {
|
||||
"project_overview": "The Project Overview gives you a rundown of all your current projects. \nYou can create new ones, edit or delete existing ones or filter for an specific project here. \nLook up the current state of your projects as well as the progress together with some additional information like name, client, tester and when it was created.",
|
||||
"project_overview_filtered": "Filtering through the Project Overview can help you to find the project(s) you are looking for. \nEnter specific keywords like the title of a project, a special state like 'Needs More Info or look for an important client.",
|
||||
"create_edit_project": "Create a new project or an existing one and give it a title, client name, assign a tester and write a summary for the pentest (only available in edit mode). \nIn addition to that you can also select a specific state for the project to show if the pentest is currently 'work in progress' or waits for the customer to review the report.",
|
||||
"userprofile": "Change your settings. \nWeather it's just selecting the language of the application or changing your password.",
|
||||
"category&objective_overview": "View every objective of every category here. \nThe same content is also included in the OWASP Web Testing Guide. \nYou can get a good overview of all the objectives that are included in a specific category, see how many findings and comments have been added and even deactivate specific ones that you will result in them not being included in the report.",
|
||||
"objective_info": "Read the most important information in regards to the selected objective. \nThis information includes what has to be done in the objective and what are the most common issue as well as how you could exploit them.",
|
||||
"objective_finding_overview": "See all the findings that relate to the selected objective. \nYou can see the title, severity, part of the description and impact of the finding. \nIn addition you can also edit or even delete a specific finding.",
|
||||
"create_edit_finding": "Edit or create new findings for the objective. \nDocument the title, description, the impacted application parts, affected URL's or API's and a severity rating together with reproduction steps and a mitigation suggestion here. \nYou can only create findings once you have started the timer so that your work will be tracked.",
|
||||
"objective_comment_overview": "See all the comments that relate to the selected objective. \nYou can see the title and part of the description of the comment. \nIn addition you can also edit or even delete a specific comment.",
|
||||
"create_edit_comment": "Edit or create new comments for the objective. \nDocument the title and a description here. \nYou can only create comments once you have started the timer so that your work will be tracked.",
|
||||
"generate_report": "Generate and export your report. You can see your project name and version as well as some statistics about how many of your objectives are completed, in progress, paused, not started or disabled. \nOnly your completed objectives will be included in the final report. \nBefore exporting make sure you select the correct language of you report.",
|
||||
"report": "Download your generated report as an pdf and send it directly to the customer. \nThe report includes all the information you have entered in the C4PO application. \nThe report consists of a Cover, Table of Contents, State of Confidentiality, Executive Summary, Technical Details for Findings and Comments and Appendencies."
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
"new": "New",
|
||||
"needs_more_info": "Needs More Info",
|
||||
"pre_submission": "Pre-submission",
|
||||
"pending": "Pending",
|
||||
"triaged": "Triaged",
|
||||
"retesting": "Retesting",
|
||||
"resolved": "Resolved",
|
||||
"informative": "Informative",
|
||||
"duplicate": "Duplicate",
|
||||
"not_applicable": "Not Applicable",
|
||||
"spam": "Spam",
|
||||
"out_of_scope": "Out Of Scope",
|
||||
"accepted_risk": "Accepted Risk"
|
||||
},
|
||||
"report": {
|
||||
"dialog": {
|
||||
"header": "Export Penetrationtest Report",
|
||||
"formatLabel": "Pick export format for report:",
|
||||
"languageLabel": "Pick report language:"
|
||||
},
|
||||
"popup": {
|
||||
"generation.success": "Report generation successful",
|
||||
"generation.failed": "Report could not be generated"
|
||||
},
|
||||
"generate": "Generate Report",
|
||||
"hint": "{{completedObjectivesNumber}} of your completed objective(s) will be included in the pentest report."
|
||||
},
|
||||
"project": {
|
||||
"title.label": "Project Title",
|
||||
"client.label": "Name of Client",
|
||||
"tester.label": "Name of Pentester",
|
||||
"state.label": "State of Pentest",
|
||||
"summary.label": "Summary",
|
||||
"summary.placeholder": "Should include Executive Summary, Approach, Scope and Assessment Overview as well as General Recommendations",
|
||||
"title": "Title",
|
||||
"client": "Client",
|
||||
"tester": "Tester",
|
||||
"state": "State of Pentest",
|
||||
"summary": "Summary",
|
||||
"createdAt": "Created at",
|
||||
"overview": {
|
||||
"add.project": "Add Project",
|
||||
"no.projects": "No projects available"
|
||||
},
|
||||
"filter": {
|
||||
"placeholder": "Search through all {{allProjectsCount}} project(s).."
|
||||
},
|
||||
"create": {
|
||||
"header": "Create New Project"
|
||||
},
|
||||
|
@ -55,12 +165,16 @@
|
|||
},
|
||||
"delete": {
|
||||
"title": "Delete Project",
|
||||
"key": "Do you want to permanently delete the project \"{{name}}\"?"
|
||||
"key": "Do you want to permanently delete the project \"{{name}}\"?",
|
||||
"confirmStringPlaceholder": "Enter project title to confirm",
|
||||
"sec.key": "Do you want to permanently delete the project \"{{name}}\"? \nAll related data will also be deleted."
|
||||
},
|
||||
"validationMessage": {
|
||||
"titleRequired": "Title is required.",
|
||||
"clientRequired": "Client is required.",
|
||||
"testerRequired": "Tester is required."
|
||||
"testerRequired": "Tester is required.",
|
||||
"stateRequired": "State is required.",
|
||||
"summaryRequired": "Summary is required."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "No projects found",
|
||||
|
@ -72,20 +186,155 @@
|
|||
"delete.failed": "Project could not be deleted"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"INFORMATION_GATHERING": "Information Gathering",
|
||||
"CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING": "Config & Deploy Management Testing",
|
||||
"IDENTITY_MANAGEMENT_TESTING": "Identity Management Testing",
|
||||
"AUTHENTICATION_TESTING": "Authentication Testing",
|
||||
"AUTHORIZATION_TESTING": "Authorization Testing",
|
||||
"SESSION_MANAGEMENT_TESTING": "Session Management Testing",
|
||||
"INPUT_VALIDATION_TESTING": "Input Validation Testing",
|
||||
"ERROR_HANDLING": "Error Handling",
|
||||
"CRYPTOGRAPHY": "Cryptography",
|
||||
"BUSINESS_LOGIC_TESTING": "Business Logic Testing",
|
||||
"CLIENT_SIDE_TESTING": "Client Side Testing",
|
||||
"API_TESTING": "API Testing"
|
||||
},
|
||||
"finding": {
|
||||
"findingId": "Finding Id",
|
||||
"severity": "Severity",
|
||||
"title": "Title",
|
||||
"description": "Description",
|
||||
"impact": "Impact",
|
||||
"affectedUrls": "Affected URL's / API's",
|
||||
"reproduction": "Reproduction",
|
||||
"mitigation": "Mitigation",
|
||||
"add": "Add finding",
|
||||
"add.url": "Add affected URL / API",
|
||||
"affectedUrls.placeholder": "Enter affected URL or API here..",
|
||||
"create": {
|
||||
"header": "Create New Finding"
|
||||
},
|
||||
"edit": {
|
||||
"header": "Edit Finding"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Delete Finding",
|
||||
"key": "Do you want to permanently delete the finding \"{{name}}\"?"
|
||||
},
|
||||
"severity.label": "Severity of Finding",
|
||||
"title.label": "Finding Title",
|
||||
"description.label": "Description of Finding",
|
||||
"impact.label": "Impacted Applicationparts",
|
||||
"affectedUrls.label": "Affected URL's / API's",
|
||||
"reproduction.label": "Reproductionsteps",
|
||||
"mitigation.label": "Suggest Mitigation",
|
||||
"no.findings": "No findings available",
|
||||
"validationMessage": {
|
||||
"titleRequired": "Title is required.",
|
||||
"severityRequired": "Severity is required.",
|
||||
"descriptionRequired": "Description is required.",
|
||||
"impactRequired": "Impact is required.",
|
||||
"affectedUrlsRequired": "Affected Url's required.",
|
||||
"reproductionRequired": "Reproductionstep(s) are required.",
|
||||
"mitigationRequired": "Mitigation is required."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "No finding found",
|
||||
"save.success": "Finding saved successfully",
|
||||
"save.failed": "Finding could not be saved",
|
||||
"update.success": "Finding updated successfully",
|
||||
"update.failed": "Finding could not be updated",
|
||||
"delete.success": "Finding deleted successfully",
|
||||
"delete.failed": "Finding could not be deleted",
|
||||
"not.available": "Finding is not available anymore"
|
||||
}
|
||||
},
|
||||
"severities": {
|
||||
"low": "Low",
|
||||
"medium": "Medium",
|
||||
"high": "High",
|
||||
"critical": "Critical"
|
||||
},
|
||||
"comment": {
|
||||
"commentId": "Comment Id",
|
||||
"title": "Title",
|
||||
"description": "Description",
|
||||
"relatedFindings": "Related Findings",
|
||||
"add": "Add Comment",
|
||||
"add.finding": "Add related finding",
|
||||
"no.comments": "No comments available",
|
||||
"no.relatedFindings": "Not related to any finding",
|
||||
"relatedFindingsPlaceholder": "Select a related finding",
|
||||
"noFindingsInObjectivePlaceholder": "Objective doesn't have any findings to relate to.",
|
||||
"create": {
|
||||
"header": "Create New Comment"
|
||||
},
|
||||
"edit": {
|
||||
"header": "Edit Comment"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Delete Comment",
|
||||
"key": "Do you want to permanently delete the comment \"{{name}}\"?"
|
||||
},
|
||||
"title.label": "Comment Title",
|
||||
"description.label": "Description of Comment",
|
||||
"relatedFindings.label": "Related Findings",
|
||||
"validationMessage": {
|
||||
"titleRequired": "Title is required.",
|
||||
"descriptionRequired": "Description is required.",
|
||||
"relatedFindings": "Related findings required."
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "No comment found",
|
||||
"save.success": "Comment saved successfully",
|
||||
"save.failed": "Comment could not be saved",
|
||||
"update.success": "Comment updated successfully",
|
||||
"update.failed": "Comment could not be updated",
|
||||
"delete.success": "Comment deleted successfully",
|
||||
"delete.failed": "Comment could not be deleted",
|
||||
"not.available": "Comment is not available anymore"
|
||||
}
|
||||
},
|
||||
"pentest": {
|
||||
"testId": "No.",
|
||||
"title": "Title",
|
||||
"findings": "Findings",
|
||||
"comments": "Comments",
|
||||
"findings&comments": "Findings & Comments",
|
||||
"status": "Status",
|
||||
"statusText": {
|
||||
"not_started": "Not Started",
|
||||
"disabled": "Disabled",
|
||||
"open": "Open",
|
||||
"checked": "Checked",
|
||||
"reported": "Reported",
|
||||
"under_review": "Under Review",
|
||||
"triaged": "Triaged"
|
||||
"paused": "Paused",
|
||||
"in_progress": "In progress",
|
||||
"completed": "Completed"
|
||||
},
|
||||
"disable": {
|
||||
"title": "Disable Objective",
|
||||
"key": "Do you want to disable the objective \"{{name}}\"?"
|
||||
},
|
||||
"enable": {
|
||||
"title": "Enable Objective",
|
||||
"key": "Do you want to enable the objective \"{{name}}\"?"
|
||||
},
|
||||
"popup": {
|
||||
"not.found": "No pentest found",
|
||||
"initial.save.success": "Initial Pentest successfully setup",
|
||||
"initial.save.failed": "Initial Pentest could not be setup",
|
||||
"save.success": "Pentest saved successfully",
|
||||
"save.failed": "Pentest could not be saved",
|
||||
"complete.success": "Pentest completed successfully",
|
||||
"complete.failed": "Pentest could not be completed",
|
||||
"update.success": "Pentest updated successfully",
|
||||
"update.failed": "Pentest could not be updated",
|
||||
"delete.success": "Pentest deleted successfully",
|
||||
"delete.failed": "Pentest could not be deleted",
|
||||
"disable.success": "Objective disabled successfully",
|
||||
"disable.failed": "Objective could not be disabled",
|
||||
"enable.success": "Objective enabled successfully",
|
||||
"enable.failed": "Objective could not be enabled"
|
||||
},
|
||||
"info": {
|
||||
"001": "Conduct Search Engine Discovery and Reconnaissance for Information Leakage",
|
||||
|
@ -93,7 +342,7 @@
|
|||
"003": "Review Webserver Metafiles for Information Leakage",
|
||||
"004": "Enumerate Applications on Webserver",
|
||||
"005": "Review Webpage Comments and Metadata for Information Leakage",
|
||||
"006": "Identity application entry points",
|
||||
"006": "Identify application entry points",
|
||||
"007": "Map execution paths through application",
|
||||
"008": "Fingerprint Web Application Framework",
|
||||
"009": "Fingerprint Web Application",
|
||||
|
@ -103,20 +352,21 @@
|
|||
"001": "Test Network/Infrastructure Configuration",
|
||||
"002": "Test Application Platform Configuration",
|
||||
"003": "Test File Extensions Handling for Sensitive Information",
|
||||
"004": "Backup and Unreferenced Files for Sensitive Information",
|
||||
"004": "Review Backups and Unreferenced Files for Sensitive Information",
|
||||
"005": "Enumerate Infrastructure and Application Admin Interfaces",
|
||||
"006": "Test HTTP Methods",
|
||||
"007": "Test HTTP Strict Transport Security",
|
||||
"008": "Test RIA cross domain policy"
|
||||
"008": "Test RIA cross domain policy",
|
||||
"009": "Test File Permission",
|
||||
"010": "Test for Subdomain Takeover",
|
||||
"011": "Test Cloud Storage"
|
||||
},
|
||||
"ident": {
|
||||
"001": "Test Role Definitions",
|
||||
"002": "Test User Registration Process",
|
||||
"003": "Test Account Provisioning Process",
|
||||
"004": "Testing for Account Enumeration and Guessable User Account",
|
||||
"005": "Testing for Weak or unenforced username policy",
|
||||
"006": "Test Permissions of Guest/Training Accounts",
|
||||
"007": "Test Account Suspension/Resumption Process"
|
||||
"005": "Testing for Weak or unenforced username policy"
|
||||
},
|
||||
"authn": {
|
||||
"001": "Testing for Credentials Transported over an Encrypted Channel",
|
||||
|
@ -144,45 +394,49 @@
|
|||
"005": "Testing for Cross Site Request Forgery",
|
||||
"006": "Testing for logout functionality",
|
||||
"007": "Test Session Timeout",
|
||||
"008": "Testing for Session puzzling"
|
||||
"008": "Testing for Session puzzling",
|
||||
"009": "Testing for Session Hijacking"
|
||||
},
|
||||
"inpval": {
|
||||
"001": "Testing for Reflected Cross Site Scripting",
|
||||
"002": "Testing for Stored Cross Site Scripting",
|
||||
"003": "Testing for HTTP Verb Tampering",
|
||||
"004": "Testing for HTTP Parameter pollution",
|
||||
"005": "N/A",
|
||||
"006": "Testing for SQL Injection",
|
||||
"006_1": "Oracle Testing",
|
||||
"006_2": "SQL Server Testing",
|
||||
"006_3": "Testing PostgreSQL",
|
||||
"006_4": "MS Access Testing",
|
||||
"006_5": "Testing for NoSQL Injection",
|
||||
"007": "Testing for LDAP Injection",
|
||||
"008": "Testing for ORM Injection",
|
||||
"009": "Testing for XML Injection",
|
||||
"010": "Testing for SSI Injection",
|
||||
"011": "Testing for XPath Injection",
|
||||
"012": "IMAP/SMTP Injection",
|
||||
"013": "Testing for Code Injection",
|
||||
"013_1": "Testing Local File Inclusion",
|
||||
"013_2": "Testing Remote File Inclusion",
|
||||
"014": "Testing for Command Injection",
|
||||
"015": "Testing for Buffer overflow",
|
||||
"015_1": "Testing for Heap overflow",
|
||||
"015_2": "Testing for Stack overflow",
|
||||
"015_3": "Testing for Format string",
|
||||
"016": "Testing for incubated vulnerabilities",
|
||||
"017": "Testing for HTTP Splitting/Smuggling"
|
||||
"005": "Testing for SQL Injection",
|
||||
"005_1": "Oracle Testing",
|
||||
"005_2": "MySQL Testing",
|
||||
"005_3": "SQL Server Testing",
|
||||
"005_4": "Testing PostgreSQL",
|
||||
"005_5": "MS Access Testing",
|
||||
"005_6": "Testing for NoSQL Injection",
|
||||
"005_7": "Testing for ORM Injection",
|
||||
"005_8": "Testing for Client-side",
|
||||
"006": "Testing for LDAP Injection",
|
||||
"007": "Testing for XML Injection",
|
||||
"008": "Testing for SSI Injection",
|
||||
"009": "Testing for XPath Injection",
|
||||
"010": "IMAP/SMTP Injection",
|
||||
"011": "Testing for Code Injection",
|
||||
"011_1": "Testing Local File Inclusion",
|
||||
"011_2": "Testing Remote File Inclusion",
|
||||
"012": "Testing for Command Injection",
|
||||
"013": "Testing for Format String Injection",
|
||||
"014": "Testing for incubated vulnerabilities",
|
||||
"015": "Testing for HTTP Splitting/Smuggling",
|
||||
"016": "Testing for HTTP Incoming Requests",
|
||||
"017": "Testing for Host Header Injection",
|
||||
"018": "Testing for Server-side Template Injection",
|
||||
"019": "Testing for Server-side Request Forgery"
|
||||
},
|
||||
"err": {
|
||||
"001": "Analysis of Error Codes",
|
||||
"002": "Analysis of Stack Traces"
|
||||
},
|
||||
"crypst": {
|
||||
"001": "Testing for Weak SSL/TSL Ciphers, Insufficient Transport Layer Protection",
|
||||
"001": "Testing for Weak SSL/TLS Ciphers, Insufficient Transport Layer Protection",
|
||||
"002": "Testing for Padding Oracle",
|
||||
"003": "Testing for Sensitive information sent via unencrypted channels"
|
||||
"003": "Testing for Sensitive information sent via unencrypted channels",
|
||||
"004": "Testing for Weak Encryption"
|
||||
},
|
||||
"buslogic": {
|
||||
"001": "Test Business Logic Data Validation",
|
||||
|
@ -207,20 +461,145 @@
|
|||
"009": "Testing for Clickjacking",
|
||||
"010": "Testing WebSockets",
|
||||
"011": "Test Web Messaging",
|
||||
"012": "Test Local Storage"
|
||||
"012": "Test Local Storage",
|
||||
"013": "Testing for Cross Site Script Inclusion"
|
||||
},
|
||||
"api": {
|
||||
"001": "Testing GraphQL"
|
||||
}
|
||||
},
|
||||
"categories": {
|
||||
"INFORMATION_GATHERING": "Information Gathering",
|
||||
"CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING": "Config & Deploy Management Testing",
|
||||
"IDENTITY_MANAGEMENT_TESTING": "Identity Management Testing",
|
||||
"AUTHENTICATION_TESTING": "Authentication Testing",
|
||||
"AUTHORIZATION_TESTING": "Authorization Testing",
|
||||
"SESSION_MANAGEMENT_TESTING": "Session Management Testing",
|
||||
"INPUT_VALIDATION_TESTING": "Input Validation Testing",
|
||||
"ERROR_HANDLING": "Error Handling",
|
||||
"CRYPTOGRAPHY": "Cryptography",
|
||||
"BUSINESS_LOGIC_TESTING": "Business Logic Testing",
|
||||
"CLIENT_SIDE_TESTING": "Client Side Testing"
|
||||
"objectives": {
|
||||
"info": {
|
||||
"001": "The objective is to understand what sensitive design and configuration information of the application/system/organization is exposed both directly (on the organization’s website) or indirectly (on a third party website).\n\n There are direct and indirect elements to search engine discovery and reconnaissance. \n Direct methods relate to searching the indexes and the associated content from caches.\n Indirect methods relate to gleaning sensitive design and configuration information by searching forums, newsgroups, and tendering websites.\n\n Use a search engine to search for:\n• Network diagrams and configurations\n• Archived posts and emails by administrators and other key staff\n• Log on procedures and username formats\n• Usernames and passwords\n• Error message content\n• Development, test, UAT and staging versions of the website",
|
||||
"002": "The objective is to find the version and type of a running web server to determine known vulnerabilities and the appropriate exploits to use during testing.\n\n Web server fingerprinting is a critical task for the penetration tester.\nKnowing the version and type of a running web server allows testers to determine known vulnerabilities and the appropriate exploits to use during testing.\n\n There are several different vendors and versions of web servers on the market today. Knowing the type of web server that is being tested significantly helps in the testing process and can also change the course of the test. The simplest and most basic form of identifying a web server is to look at the Server field in the HTTP response header.\n\n By knowing how each type of web server responds to specific commands and keeping this information in a web server fingerprint database, a penetration tester can send these commands to the web server, analyze the response, and compare it to the database of known signatures.",
|
||||
"003": "The objective here is to check the robots.txt file for information leakage of the web application’s directory or folder path(s).\n\n 1. Information leakage of the web application’s directory or folder path(s). \n 2. Create the list of directories that are to be avoided by Spiders, Robots, or Crawlers. \n\n Furthermore, the list of directories that are to be avoided by Spiders, Robots, or Crawlers can also be created as a dependency for Map execution paths through application.\n Web Spiders, Robots, or Crawlers retrieve a web page and then recursively traverse hyperlinks to retrieve further web content. Their accepted behavior is specified by the Robots Exclusion Protocol of the robots.txt file in the web root directory.",
|
||||
"004": "The objective is enumerate the applications within scope that exist on a web server.\n\n Many applications have known vulnerabilities and known attack strategies that can be exploited in order to gain remote control or to exploit data. In addition, many applications are often misconfigured or not updated. \n Web application discovery is a process aimed at identifying web applications on a given infrastructure. The latter is usually specified as a set of IP addresses (maybe a net block), but may consist of a set of DNS symbolic names or a mix of the two.",
|
||||
"005": "The objective is to review webpage comments and metadata to better understand the application and to find any information leakage.\n\n HTML comments are often used by the developers to include debugging information about the application. Sometimes they forget aboutthe comments and they leave them on in production.\n\n Check HTML source code for comments containing sensitive information that can help the attacker gain more insight about the application. It might be SQL code, usernames and passwords, internal IP addresses, or debugging information.",
|
||||
"006": "The objective is to understand how requests are formed and typical responses from the application.\n\n Enumerating the application and its attack surface is a key precursor before any thorough testing can be undertaken, as it allows the tester to identify likely areas of weakness. This aims to help identify and map out areas within the application that should be investigated once enumeration and mapping have been completed.\n\n While walking through the application, pay special attention to all HTTP requests (GET and POST Methods, also known as Verbs), as well as every parameter and form field that is passed to the application.\n In addition, take note of any interesting parameters in the URL, custom headers, or body of the requests/responses, and save them. \n Once every area of the application is mapped out, go through the application and test each of the areas that have been identified and make notes for what worked and what didn’t work.",
|
||||
"007": "The objective is to Map the target application and understand the principal workflows.\n\n Before commencing security testing, understanding the structure of the application is paramount.\nThere are several ways to approach the testing and measurement of code coverage:\n\n 1. Path:\n Test each of the paths through an application that includes combinatorial and boundary value analysis testing for each decision path. While this approach offers thoroughness, the number of testable paths grows exponentially with each decision branch.\n\n 2. Data flow (or taint analysis): \n Tests the assignment of variables via external interaction (normally users).\n Focuses on mapping the flow, transformation and use of data throughout an application.\n\n 3. Race:\n Tests multiple concurrent instances of the application manipulating the same data.",
|
||||
"008": "The objective is to define type of used web framework so as to have a better understanding of the security testing methodology. \n\n Knowing the type of framework can automatically give a great advantage if such a framework has already been tested by the penetration tester. It is not only the known vulnerabilities in unpatched versions but specific misconfigurations in the framework and known file structure that makes the fingerprinting process so important.\n\n There are several most common locations to look in in order to define the current framework:\n• HTTP headers\n• Cookies\n• HTML source code\n• Specific files and folders",
|
||||
"009": "The objective is to identify the web application and version to determine known vulnerabilities and the appropriate exploits to use during testing.\n\n With the vast number of free and open source software projects that are actively developed and deployed around the world, it is very likely that an application security test will face a target site that is entirely or partly dependent on these well known applications (e.g. Wordpress, phpBB, Mediawiki, etc).\n\nKnowing the web application components that are being tested significantly helps in the testing process.\nThese well known web applications have known HTML headers, cookies, and directory structures that can be enumerated to identify the application.",
|
||||
"010": "The application architecture needs to be mapped through some test to determine what different components are used to build the web application.\n\n In small setups, such as a simple CGI-based application, a single server might be used that runs the web server which executes the C, Perl, or Shell CGIs application, and perhaps also the authentication mechanism.\n On more complex setups multiple servers might be involved. These may include a reverse proxy, a frontend web server, an application server and a database server or LDAP server. \nEach of these servers will be used for different purposes and might be even be divided in different networks with firewalls between them (DMZs). \n\n In addition, understanding the deployed configuration of the server hosting the web application is almost as important as the application security testing itself."
|
||||
},
|
||||
"config": {
|
||||
"001": "The intrinsic complexity of interconnected and heterogeneous webserver infrastructure, which can include hundreds of web applications, makes configuration management and review a fundamental step in testing and deploying every single application. It takes only a single vulnerability to undermine the security of the entire infrastructure. In order to address these problems, it is of utmost importance to perform an indepth review of configuration and known security issues.\n\nThe following steps need to be taken to test the configuration management infrastructure:\n\nStep 1:\n The different elements that make up the infrastructure need to be determined in order to understand how they interact with a web application and how they affect its security.\n\nStep 2:\n All the elements of the infrastructure need to be reviewed in order to make sure that they don’t contain any known vulnerabilities.\n\nStep 3:\n A review needs to be made of the administrative tools used to maintain all the different elements.\n\nStep 4:\n The authentication systems, need to reviewed in order to assure that they serve the needs of the application and that they cannot be manipulated by external users to leverage access.\n\nStep 5:\n A list of defined ports which are required for the application should be maintained and kept under change control.",
|
||||
"002": "Configuration review and testing is a critical task in creating and maintaining an architecture. This is because many different systems will be usually provided with generic configurations that might not be suited to the task they will perform on the specific site they’re installed on.\n\n While the typical web and application server installation will contain a lot of functionality (like application examples, documentation, test pages) what is not essential should be removed before deployment to avoid post-install exploitation. \n\nCGI scanners include a detailed list of known files and directory samples that are provided by different web or application servers.\nAlso will event logs often contain data that is useful to an attacker (information leakage) or can be used directly in exploits.",
|
||||
"003": "File extensions are commonly used in web servers to easily determine which technologies, languages and plugins must be used to fulfill the web request. \nWhile this behavior is consistent with RFCs and Web Standards, using standard file extensions provides the penetration tester useful information about the underlying technologies used in a web appliance. \n\n Determining how web servers handle requests corresponding to files having different extensions may help in understanding web server behavior depending on the kind of files that are accessed.\n\nThe following file extensions should never be returned by a web server, since they are related to files which may contain sensitive information:\n • .asa\n• .inc \n\n The following file extensions are related to files which, when accessed, are either displayed or downloaded by the browser. \n Therefore, files with these extensions must be checked to verify that they are indeed supposed to be served:\n• .zip, .tar, .gz, .tgz, .rar, ...: (Compressed) archive files\n• .java: No reason to provide access to Java source files\n• .txt: Text files\n• .pdf: PDF documents\n• .doc, .rtf, .xls, .ppt, ...: Office documents\n• .bak, .old and other extensions indicative of backup files \n\n To identify files having a given extensions a mix of techniques can be employed. \nThese techniques can include Vulnerability Scanners, spidering and mirroring tools, manually inspecting the application or querying search engines.",
|
||||
"004": "An important source of vulnerability lies in files which have nothing to do with the application, but are created as a consequence of editing application files, or after creating on-the-fly backup copies, or by leaving in the web tree old files or unreferenced files.\n\n Theoretically the examination should be performed by hand to be thorough. However, since in most cases copies of files or backup files tend to be created by using the same naming conventions, the search can be easily scripted.",
|
||||
"005": "Administrator interfaces may be present in the application or on the application server to allow certain users to undertake privileged activities on the site. Tests should be undertaken to reveal if and how this privileged functionality can be accessed by an unauthorized or standard user.\n\nAn application may require an administrator interface to enable a privileged user to access functionality that may make changes to how the site functions. \nSuch changes may include: \n• user account provisioning\n• site design and layout \n• data manipulation\n• configuration changes\n\nThe following describes vectors that may be used to test for the presence of administrative interfaces: \n• Directory and file enumeration \n• Brute forcing tools like THC-HYDRA \n• Comments and links in source code \n• Reviewing server and application documentation \n• Publicly available information (e.g. default passwords) \n• Alternative server port \n• Parameter tampering",
|
||||
"006": "To perform this test, the tester needs some way to figure out which HTTP methods are supported by the web server that is being examined. The OPTIONS HTTP method provides the tester with the most direct and effective way to do that. RFC 2616 states that, “The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI”.\n\n Some of the HTTP methods can potentially pose a security risk for a web application, as they allow an attacker to modify the files stored on the web server and, in some scenarios, steal the credentials of legitimate users. More specifically, the methods that should be disabled are the following: \n• PUT: allows client to upload files to web server \n• DELETE: allwas client to delete files from web server \n• CONNECT: allows client to use web server as proxy \n• TRACE: echoes back to client whatever he sent to server",
|
||||
"007": "The HTTP Strict Transport Security (HSTS) feature lets a web application to inform the browser, through the use of a special response header, that it should never establish a connection to the the specified domain servers using HTTP.\n\n The HTTP strict transport security header uses two directives: \n• max-age \n• includeSubDomains \n\nTesting for the presence of HSTS header can be done by checking for the existence of the HSTS header in the server’s response in an interception proxy, or by using curl.",
|
||||
"008": "Rich Internet Applications (RIA) have adopted Adobe’s crossdomain.xml policy files to allow for controlled cross domain access to data and service consumption using technologies such as Oracle Java, Silverlight, and Adobe Flash. Therefore, a domain can grant remote access to its services from a different domain. \nHowever, often the policy files that describe the access restrictions are poorly configured. Poor configuration of the policy files enables Cross-site Request Forgery attacks. \n\n To test for RIA policy file weakness the tester should try to retrieve the policy files crossdomain.xml and clientaccesspolicy.xml from the application’s root, and from every folder found.",
|
||||
"009": "When a resource is given a permissions setting that provides access to a wider range of actors than required, it could lead to the exposure of sensitive information, or the modification of that resource by unintended parties. This is especially dangerous when the resource is related to program configuration, execution, or sensitive user data. \n\nA clear example is an execution file that is executable by unauthorized users. For another example, account information or a token value to access an API - increasingly seen in modern web services or microservices - may be stored in a configuration file whose permissions are set to world-readable from the installation by default. Such sensitive data can be exposed by internal malicious actors of the host or by a remote attacker who compromised the service with other vulnerabilities but obtained only a normal user privilege.\n\nThe files and directories that require file permission testing include but are not limited to: \n• Web files/directory\n• Configuration files/directory \n• Sensitive files (encrypted data, password, key)/directory \n• Log files (security logs, operation logs, admin logs)/directory \n• Executables (scripts, EXE, JAR, class, PHP, ASP)/directory \n• Database files/directory\n• Temp files /directory \n• Upload files/directory",
|
||||
"010": "A successful exploitation of this kind of vulnerability allows an adversary to claim and take control of the victim’s subdomain.\nThis attack relies on the following: \n\n1. The victim’s external DNS server subdomain record is configured to point to a non-existing or non-active resource/external service/endpoint. The proliferation of XaaS (Anything as a Service) products and public cloud services offer a lot of potential targets to consider. \n\n2. The service provider hosting the resource/external service/endpoint does not handle subdomain ownership verification properly.\n\nIf the subdomain takeover is successful a wide variety of attacks are possible (serving malicious content, phising, stealing user session cookies, credentials, etc.). This vulnerability could be exploited for a wide variety of DNS resource records including: A , CNAME , MX , NS , TXT etc. In terms of the attack severity an NS subdomain takeover (although less likely) has the highest impact because a successful attack could result in full control over the whole DNS zone and the victim’s domain.\n\nTest Objectives:\n• Enumerate all possible domains (previous and current). \n• Identify forgotten or misconfigured domains\n",
|
||||
"011": "Cloud storage services facilitate web application and services to store and access objects in the storage service. Improper access control configuration, however, may result in sensitive information exposure, data being tampered, or unauthorized access. \n\nA known example is where an Amazon S3 bucket is misconfigured, although the other cloud storage services may also be exposed to similar risks. By default, all S3 buckets are private and can be accessed only by users that are explicitly granted access. Users can grant public access to both the bucket itself and to individual objects stored within that bucket. This may lead to an unauthorized user being able to upload new files, modify or read stored files.\n\nFirst identify the URL to access the data in the storage service, and then consider the following tests: \n• read the unauthorized data\n• upload a new arbitrary file\n\nTest Objectives:\n• Assess that the access control configuration for the storage services is properly in place"
|
||||
},
|
||||
"ident": {
|
||||
"001": "The objective is to validate the system roles defined within the application sufficiently define and separate each system and business role to manage appropriate access to system functionality and information. \n\nApplications have several types of functionalities and services, and those require access permissions based on the needs of the user. That user could be: \n• an administrator, where they manage the application functionalities. \n• an auditor, where they review the application transactions and provide a detailed report. \n• a support engineer, where they help customers debug and fix issues on their accounts. \n• a customer, where they interact with the application and benefit from its services.\n\nIn more trusted environments where confidentiality is not critical, softer controls such as application workflow and audit logging can support data integrity requirements while not restricting user access to functionality. Either with or without the help of the system developers or administrators, develop a role versus permission matrix. The matrix should enumerate all the roles that can be provisioned and explore the permissions that are allowed.\n\nTest Objectives:\n• Identify and document roles used by the application. \n• Attempt to switch, change, or access another role. \n• Review the granularity of the roles and the needs behind the permissions given",
|
||||
"002": "Some websites offer a user registration process that automates (or semi-automates) the provisioning of system access to users. The identity requirements for access vary from positive identification to none at all, depending on the security requirements of the system. \n\n Step 1: \n Verify that the identity requirements for user registration are aligned with business and security requirements. \n\n Step 2: \n Validate the registration process. \n\n Verify that the identity requirements for user registration are aligned with business and security requirements: \n• Can anyone register for access? \n• Are registrations vetted by a human? \n• Can the same person or identity register multiple times? \n• Can users register for different roles or permissions? \n• What proof of identity is required for a registration? \n• Are registered identities verified? \n\n Validate the registration process: \n • Can identity information be easily forged or faked? \n • Can the exchange of identity information be manipulated?",
|
||||
"003": "Verify which accounts may provision other accounts and of what type. \n\nThe provisioning of accounts presents an opportunity for an attacker to create a valid account without application of the proper identification and authorization process. \n\nHow to Test\n\nDetermine which roles are able to provision users and what sort of accounts they can provision:\n• Is there any verification, vetting and authorization of provisioning requests?\n• Is there any verification, vetting and authorization of de-provisioning requests? \n• Can an administrator provision other administrators or just users? \n• Can an administrator or other user provision accounts with privileges greater than their own? \n• Can an administrator or user de-provision themselves? \n• How are the files or resources owned by the de-provisioned user managed? Are they deleted? Is access transferred?",
|
||||
"004": "The scope of this test is to verify if it is possible to collect a set of valid usernames by interacting with the authentication mechanism of the application. This test will be useful for brute force testing, in which the tester verifies if, given a valid username, it is possible to find the corresponding password. \n\nIn some cases, a message is received that reveals if the provided credentials are wrong because an invalid username or an invalid password was used. Sometimes, testers can enumerate the existing users by sending a username and an empty password. If the application is vulnerable, the tester receives a response message that reveals, directly or indirectly, some information useful for enumerating users.\n\nTest Objectives \n• Review processes that pertain to user identification (e.g. registration, login, etc.). \n• Enumerate users where possible through response analysis",
|
||||
"005": "The objective is to determine whether a consistent account name structure renders the application vulnerable to account enumeration. Determine whether the application’s error messages permit account enumeration. \n\nTest Objectives \n• Determine whether a consistent account name structure renders the application vulnerable to account enumeration.\n• Determine whether the application’s error messages permit account enumeration.\n\nUser account names are often highly structured (e.g. Joe Bloggs account name is jbloggs and Fred Nurks account name is fnurks) and valid account names can easily be guessed.\n\nHow to Test\n• Determine the structure of account names.\n• Evaluate the application’s response to valid and invalid account names.\n• Use different responses to valid and invalid account names to enumerate valid account names.\n• Use account name dictionaries to enumerate valid account names."
|
||||
},
|
||||
"authn": {
|
||||
"001": "The analysis focuses simply on trying to understand if the data travels unencrypted from the web browser to the server, or if the web application takes the appropriate security measures using a protocol like HTTPS. \n\n Testing for credentials transport means verifying that the user’s\nauthentication data are transferred via an encrypted channel to avoid being intercepted by malicious users. \n\n You can use WebScarab or any web proxy in order to capture packet headers and to inspect them. \n Check if HTTPS is used in every sensitive request, like those in log in pages, to prevent unauthorized users to intercept the data.",
|
||||
"002": "Often are applications, once installed, not properly configured and the default credentials provided for initial authentication and configuration are never changed. \n\n When you have identified an application interface, for example a Cisco router web interface or a Weblogic administrator portal, check that the known usernames and passwords for these devices do not result in successful authentication. To do this you can consult the manufacturer’s documentation or, in a much simpler way, you can find common credentials using a search engine or by using one of the sites or tools listed in the Reference section. \n\n When facing applications where we do not have a list of default and common user accounts we can attempt to guess valid default credentials. \n Many applications have verbose error messages that inform the site users as to the validity of entered usernames. This information will be helpful when testing for default or guessable user accounts. \n\nSince these types of default credentials are often bound to administrative accounts you can try the following usernames for the start: \n• admin \n• administrator \n• root \n• system \n• guest \n• operator \n• super",
|
||||
"003": "Account lockout mechanisms are used to mitigate brute force password guessing attacks. Accounts are typically locked after 3 to 5 unsuccessful login attempts and can only be unlocked after a predetermined period of time, via a self-service unlock mechanism, or intervention by an administrator. \n\n Typically, to test the strength of lockout mechanisms, you will need access to an account that you are willing or can afford to lock: \n\n Step 1: \n Evaluate the account lockout mechanism’s ability to mitigate brute force password guessing. \n\n Step 2: \nEvaluate the unlock mechanism’s resistance to unauthorized account unlocking. \n\n Without a strong lockout mechanism, the application may be susceptible to brute force attacks. After a successful brute force attack, a malicious user could have access to: \n• Confidential information or data \n• Administration panels \n• Opportunities for further attacks",
|
||||
"004": "While most applications require authentication to gain access to private information or to execute tasks, not every authentication method is able to provide adequate security. \n\n There are several methods of bypassing the authentication schema that is used by a web application: \n• Direct page request (forced browsing) \n• Parameter modification \n• Session ID prediction \n• SQL Injection",
|
||||
"005": "Browsers will sometimes ask a user if they wish to remember the password that they just entered. \n\n Having the browser store passwords is not only a convenience for end-users, but also for an attacker. If an attacker can gain access to the victim’s browser (e.g. XSS attack), then they can retrieve the stored passwords. \n Additionally where custom “remember me” functions are put in place weaknesses in how the token is stored on the client PC could expose the users passwords. \n\n Ensure that no credentials are stored in clear text or are easily retrievable in encoded or encrypted forms in cookies: \n• Look for passwords stored in cookie \n• Examine the hashing mechanism \n• Verify that credentials are only send during login \n• Consider sensitive form fields",
|
||||
"006": "Browsers can store information for purposes of caching and history. Caching is used to improve performance, so that previously displayed information doesn’t need to be downloaded again. \n If sensitive information is displayed to the user, then this information could be stored for purposes of caching or history, and therefore retrievable through examining the browser’s cache or by simply pressing the browser’s “Back” button. \n\n Technically, the “Back” button is a history and not a cache. The cache and the history are two different entities. However, they share the same weakness of presenting previously displayed sensitive information. \n\nThe “Back” button can be stopped from showing sensitive data. \nThis can be done by: \n• Delivering the page over HTTPS. \n• Setting Cache-Control: must-re-validate",
|
||||
"007": "The most prevalent and most easily administered authentication mechanism is a static password. It is lamented that most common passwords are still: 123456, password and qwerty. \n\nDetermine the resistance of the application against brute force password guessing using available password dictionaries by evaluating the length, complexity, reuse and aging requirements of passwords. \n\n Step 1: \n What characters are permitted and forbidden for use within a password? \nIs the user required to use characters from different character sets such as lower and uppercase letters, digits and special symbols? \n\n Step 2: \n How often can a user change their password? \nHow quickly can a user change their password after a previous change? \n Users may bypass password history requirements by changing their password 5 times in a row. \n\n Step 3: \n When must a user change their password? \nAfter 90 days? \nAfter account lockout due to excessive log on attempts? \n\n Step 4: \n How often can a user reuse a password? \n Does the application maintain a history of the user’s previous used 8 passwords? \n\n Step 5: \n How different must the next password be from the last password? \n\n Step 6: \nIs the user prevented from using his username or other account information (such as first or last name) in the password?",
|
||||
"008": "Often called “secret” questions and answers, security questions and answers are often used to recover forgotten passwords, or as extra security on top of the password. \n\n They are typically generated upon account creation and require the user to select from some pre-generated questions and supply an appropriate answer. They may allow the user to generate their own question and answer pairs. \n Both methods are prone to insecurities. Ideally, security questions should generate answers that are only known by the user, and not guessable or discoverable. \n\n The key to successfully exploiting and bypassing a weak security question scheme is to find a question or set of questions which give the possibility of easily finding the answers. \n\n Step 1: \nTry to obtain a list of security questions by creating a new account or by following the “I don’t remember my password”-process.\n\n Step 2: \n Try to create security questions by creating a new account or by configuring your existing account’s password recovery properties.\nIf the system allows the user to generate their own security questions, it is vulnerable to having insecure questions created. \n\n Step 3: \n Determine if a number of incorrectly supplied security answers trigger a lockout mechanism.",
|
||||
"009": "The password change and reset function of an application is a self-service password change or reset mechanism for users. \n This self-service mechanism allows users to quickly change or reset their password without an administrator intervening. \n\n Step 1: \n Determine the resistance of the application to subversion of the account change process allowing someone to change the password of an account. \n\n Step 2: \nDetermine the resistance of the passwords reset functionality against guessing or bypassing. \n\n For both password change and password reset it is important to check.. \n\n.. if users, other than administrators, can change or reset passwords for accounts other than their own. \n.. if users can manipulate or subvert the password change or reset process. \n.. if the password change or reset process is vulnerable to CSRF.",
|
||||
"010": "Even if the primary authentication mechanisms do not include any vulnerabilities, it may be that vulnerabilities exist in alternative legitimate authentication user channels for the same user accounts. \n\n Tests should be undertaken to identify alternative channels and, subject to test scoping, identify vulnerabilities. \n Some of these channels may themselves be separate web applications using different host names or paths. For example: \n• Standard website \n• Mobile website \n• Accessibility optimized website \n• Parallel websites that utilize same user accounts \n• Development, UAT and versions of the standard website \n\n But they could also be other types of application or business processes: \n• Mobile device app \n• Desktop application \n• Call center operators \n• Interactive voice response or phone tree systems"
|
||||
},
|
||||
"authz": {
|
||||
"001": "Many web applications use and manage files as part of their daily operation. Using input validation methods that have not been well designed or deployed, an aggressor could exploit the system in order to read or write files that are not intended to be accessible. In particular situations, it could be possible to execute arbitrary code or system commands. \n\n In web servers and web applications, this kind of problem arises in path traversal/file include attacks. During an assessment, to discover path traversal and file include flaws, testers need to perform two different stages: \n\n Stage 1: \n Input Vectors Enumeration (a systematic evaluation of each input vector) \n\n Stage 2: \n Testing Techniques (a methodical evaluation of each attack technique used by an attacker to exploit the vulnerability) \n\n The next stage of testing is analyzing the input validation functions present in the web application. Using the previous example, the dynamic page called getUserProfile.jsp loads static information from a file and shows the content to users. An attacker could insert the malicious string “../../../../etc/passwd” to include the password hash file. \n It’s a common mistake by developers to not expect every form of encoding and therefore only do validation for basic encoded content. If at first the test string isn’t successful, try another encoding scheme.",
|
||||
"002": "This kind of test focuses on verifying how the authorization schema has been implemented for each role or privilege to get access to reserved functions and resources. \n\nFor every specific role the tester holds during the assessment, for every function and request that the application executes during the post-authentication phase, it is necessary to verify: \n • Is it possible to access that resource even if the user is not authenticated? \n • Is it possible to access that resource after the log-out? \n • Is it possible to access functions and resources that should be accessible to a user that holds a different role or privilege? \n\n Try to access the application as an administrative user and track all the administrative functions: \n • Is it possible to access administrative functions also if the tester is logged as a user with standard privileges?\n• Is it possible to use these administrative functions as a user with adifferent role and for whom that action should be denied?",
|
||||
"003": "Privilege escalation occurs when a user gets access to more resources or functionality than they are normally allowed. \n\n During this phase, the tester should verify that it is not possible for a user to modify his or her privileges or roles inside the application in ways that could allow privilege escalation attacks. \n The degree of escalation depends on what privileges the attacker is authorized to possess, and what privileges can be obtained in a successful exploit. \n\n In every portion of the application where a user can create information in the database (e.g., making a payment, or sending a message), can receive information (statement of account, order details, etc.), or delete information (drop user, messages, etc.), it is necessary to record that functionality. \n Try to access such functions as another user in order to verify if it is possible to access a function that should not be permitted by the user’s role/privilege.",
|
||||
"004": "Insecure Direct Object References occur when an application provides direct access to objects based on user-supplied input. \n As a result of this vulnerability attackers can bypass authorization and access resources in the system directly, for example database records or files. \n\n Insecure Direct Object References allow attackers to bypass authorization and access resources directly by modifying the value of a parameter used to directly point to an object. \n\n To test for this vulnerability the tester first needs to map out all locations in the application where user input is used to reference objects directly. \n The best way to test for direct object references would be by having at least two (often more) users to cover different owned objects and functions. \n By having multiple users the tester saves valuable testing time in guessing different object names as he can attempt to access objects that belong to the other user."
|
||||
},
|
||||
"sess": {
|
||||
"001": "In order to avoid continuous authentication for each page of a website or service, web applications implement various mechanisms to store and validate credentials for a pre-determined timespan. \n These mechanisms are known as Session Management. \n\n In this test, the tester wants to check that cookies and other session tokens are created in a secure and unpredictable way. An attacker who is able to predict and forge a weak cookie can easily hijack the sessions of legitimate users. \n Due to the importance of the data that they store, cookies are there fore vital in the overall security of the application. In this test the tester has to check whether the cookies issued to clients can resist a wide range of attacks aimed to interfere with the sessions of legitimate users and with the application itself. \n\n Usually the main steps of the attack pattern are the following: \n• cookie collection \n• cookie reverse engineering \n• cookie manipulation \n\n Another pattern of attack consists of overflowing a cookie. Strictly speaking, this attack has a different nature, since here testers are not trying to recreate a perfectly valid cookie. Instead, the goal is to overflow a memory area, thereby interfering with the correct behavior of the application.",
|
||||
"002": "Cookies are often a key attack vector for malicious users and the application should always take due diligence to protect cookies. This section looks at how an application can take the necessary precautions when assigning cookies, and how to test that these attributes have been correctly configured. \n\n Due to the sensitive nature of information in cookies, they are typically encoded or encrypted in an attempt to protect the information they contain. \n Once the tester has an understanding of how cookies are set, when they are set, what they are used for, why they are used, and their importance, they should take a look at what attributes can be set for a cookie and how to test if they are secure. \n\nBy using an intercepting proxy or traffic intercepting browser plugin, trap all responses where a cookie is set by the application (using the Set-cookie directive) and inspect the cookie for the following:\n• Secure Attribute\n• HttpOnly Attribute\n• Domain Attribute\n• Path Attribute\n• Expires Attribute",
|
||||
"003": "When an application does not renew its session cookie(s) after a successful user authentication, it could be possible to find a session fixation vulnerability and force a user to utilize a cookie known by the attacker. In that case, an attacker could steal the user session (session hijacking).\n\n Session fixation vulnerabilities occur when..\n .. a web application authenticates a user without first invalidating the existing session ID, thereby continuing to use the session ID already associated with the user \n.. an attacker is able to force a known session ID on a user so that, once the user authenticates, the attacker has access to the authenticated session. \n\n In the generic exploit of session fixation vulnerabilities, an attacker creates a new session on a web application and records the associated session identifier. The attacker then causes the victim to authenticate against the server using the same session identifier, giving the attacker access to the user’s account through the active session.",
|
||||
"004": "The Session Tokens (Cookie, SessionID, Hidden Field), if exposed, will usually enable an attacker to impersonate a victim and access the application illegitimately. It is important that they are protected from eavesdropping at all times, particularly whilst in transit between the client browser and the application servers. \n\n Using a personal proxy, it is possible to ascertain the following about each request and response: \n • Protocol used (e.g., HTTP vs. HTTPS) \n • HTTP Headers \n • Message Body (e.g., POST or page content) \n\n Protection from eavesdropping is often provided by SSL encryption, but may incorporate other tunneling or encryption. If the Session ID could be presented by an attacker to the application to gain access, then it must be protected in transit to mitigate that risk. It should therefore be ensured that encryption is both the default and enforced for any request or response where the Session ID is passed, regardless of the mechanism used. \n\n Every time the authentication is successful, the user should expect to receive: \n• A different session token \n• A token sent via encrypted channel for every HTTP Request ",
|
||||
"005": "CSRF is an attack which forces an end user to execute unwanted actions on a web application in which he/she is currently authenticated.\nA successful CSRF exploit can compromise end user data and operation, when it targets a normal user. If the targeted end user is the administrator account, a CSRF attack can compromise the entire web application. \n CSRF relies on the following: \n\n Point 1: \n Web browser behavior regarding the handling of session-related information such as cookies and http authentication information; \n\n Point 2: \n Knowledge by the attacker of valid web application URLs; \n\n Point 3: \n Application session management relying only on information which is known by the browser; \n\n Point 4: \n Existence of HTML tags whose presence cause immediate access to an http[s] resource; for example the image tag img \n\n The tester must know URLs in the restricted (authenticated) area. If they possess valid credentials, they can assume both roles – the attacker and the victim. In this case, testers know the URLs to be tested just by browsing around. \n\n If session management relies only on client side values (information available to the browser), then the application is vulnerable. \n For an application to not be vulnerable, it must include session-related information in the URL, in a form of unidentifiable or unpredictable by the user.",
|
||||
"006": "Session termination is an important part of the session lifecycle. Reducing to a minimum the lifetime of the session tokens decreases the likelihood of a successful session hijacking attack. This can be seen as a control against preventing other attacks like Cross Site Scripting and Cross Site Request Forgery. Such attacks have been known to rely on a user having an authenticated session present. \n\n A secure session termination requires at least the following components: \n • Availability of user interface controls that allow the user to manually log out \n • Session termination after a given amount of time without activity (session timeout) \n • Proper invalidation of server-side session state \n\n The proper value for the session timeout depends on the purpose of the application and should be a balance of security and usability.",
|
||||
"007": "In this phase testers check that the application automatically logs out a user when that user has been idle for a certain amount of time, ensuring that it is not possible to “reuse” the same session and that no sensitive data remains stored in the browser cache. \n\n The idle timeout limits the chances that an attacker has to guess and use a valid session ID from another user, and under certain circumstances could protect public computers from session reuse. Session timeout management and expiration must be enforced server-side. If some data under the control of the client is used to enforce the session timeout, an attacker could manipulate these to extend the session duration. \n\n Step 1: \nTesters have to check whether a timeout exists, for instance, by logging in and waiting for the timeout log out to be triggered. As in the log out function, after the timeout has passed, all session tokens should be destroyed or be unusable. \n\n Step 2: \n If the timeout is configured, testers need to understand whether the timeout is enforced by the client or by the server. \n\n As a general rule, everything should be checked server-side and it should not be possible, by re-setting the session cookies to previous values, to access the application again.",
|
||||
"008": "Session Variable Overloading (Session Puzzling) is an application level vulnerability which can enable an attacker to perform a variety of malicious actions, including by not limited to.. \n.. bypass efficient authentication enforcement mechanisms, and impersonate legitimate users. \n.. elevate the privileges of a malicious user account, in an environment that would otherwise be considered foolproof. \n.. skip over qualifying phases in multi-phase processes, even if the process includes code level restrictions. \n.. manipulate server-side values in indirect methods that cannotbe predicted or detected. \n.. execute traditional attacks in locations that were previously unreachable, or even considered secure. \n\n This vulnerability occurs when an application uses the same session variable for more than one purpose. It can be detected and exploited by enumerating all of the session variables used by the application and in which context they are valid. In particular this is possible by accessing a sequence of entry points and then examining exit points.",
|
||||
"009": "An attacker who gets access to user session cookies can impersonate them by presenting such cookies. This attack is known as session hijacking. When considering network attackers, i.e., attackers who control the network used by the victim, session cookies can be unduly exposed to the attacker over HTTP. To prevent this, session cookies should be marked with the “Secure” attribute so that they are only communicated over HTTPS.\n\nTest Objectives \n• Identify vulnerable session cookies. \n• Hijack vulnerable cookies and assess the risk level.\n\nHow to Test\nHere are the steps for executing this test: \n1. Login to the website as the victim and reach any page offering a secure function requiring authentication. \n2. Delete from the cookie jar all the cookies which satisfy any of the following conditions. \n• in case there is no HSTS adoption: the Secure attribute is set. \n• in case there is partial HSTS adoption: the Secure attribute is set or the Domain attribute is not set. \n3. Save a snapshot of the cookie jar. \n4. Trigger the secure function identified at step 1. \n5. Observe whether the operation at step 4 has been performed successfully. If so, the attack was successful. \n6. Clear the cookie jar, login as the attacker and reach the page at step 1. \n7. Write in the cookie jar, one by one, the cookies saved at step 3. \n8. Trigger again the secure function identified at step 1. \n9. Clear the cookie jar and login again as the victim. \n10. Observe whether the operation at step 8 has been performed successfully in the victim’s account. If so, the attack was successful; otherwise, the site is secure against session hijacking.\n\nNote that the Secure attribute should also be used when the web application is entirely deployed over HTTPS, otherwise the following cookie theft attack is possible. Assume that example.com is entirely deployed over HTTPS, but does not mark its session cookies as “Secure”. \n\nThe following attack steps are possible:\n1. The victim sends a request to http://another-site.com . \n2. The attacker corrupts the corresponding response so that it triggers a request to http://example.com . \n3. The browser now tries to access http://example.com . \n4. Though the request fails, the session cookies are leaked in the clear over HTTP.\n\nWith the Domain attribute set, session cookies can be shared across sub-domains. Use of HTTP with sub-domains should be avoided to prevent the disclosure of unencrypted cookies sent over HTTP. To exemplify this security flaw, assume that the website example.com activates HSTS without the includeSubDomains option. The website issues session cookies with the Domain attribute set to example.com. \n\nThe following attack is possible:\n1. The victim sends a request to http://another-site.com. \n2. The attacker corrupts the corresponding response so that it triggers a request to http://fake.example.com. \n3. The browser now tries to access http://fake.example.com , which is permitted by the HSTS configuration. \n4. Since the request is sent to a sub-domain of example.com with the Domain attribute set, it includes the session cookies, which are leaked in the clear over HTTP."
|
||||
},
|
||||
"inpval": {
|
||||
"001": "Reflected Cross-site Scripting (XSS) occur when an attacker injects browser executable code within a single HTTP response. \nThe injected attack is not stored within the application itself; it is non-persistent and only impacts users who open a maliciously crafted link or third-party web page. \nThe attack string is included as part of the crafted URI or HTTP parameters, improperly processed by the application, and returned to the victim. One of the primary difficulties in preventing XSS vulnerabilities is proper character encoding. \n In some cases, the web server or the web application could not be filtering some encodings of characters, so, for example, the web application might filter out “<script>”, but might not filter %3cscript%3e which simply includes another encoding of tags. A test will include at least three phases: \n\n Phase 1: \nDetect input vectors. For each web page, the tester must determine all the web application’s user-defined variables and how to input them. This includes hidden or non-obvious inputs such as HTTP parameters, POST data, hidden form field values, and predefined radio or selection values. Typically in-browser HTML editors or web proxies are used to view these hidden variables. \n\n Phase 2: \n Analyze each input vector to detect potential vulnerabilities. dTo detect an XSS vulnerability, the tester will typically use specially crafted input data with each input vector. Such input data is typically harmless, but trigger responses from the web browser that manifests the vulnerability. Testing data can be generated by using a web application fuzzer, an automated predefined list of known attack strings, or manually. \n\n Phase 3: \n For each test input attempted in the previous phase, the tester will analyze the result and determine if it represents a vulnerability that has a realistic impact on the web application’s security. This requires examining the resulting web page HTML and searching for the test input. Once found, the tester identifies any special characters that were not properly encoded, replaced, or filtered out.",
|
||||
"002": "Stored Cross-site Scripting (XSS) is the most dangerous type of Cross Site Scripting. \n\n Stored XSS occurs when a web application gathers input from a user which might be malicious, and then stores that input in a data store for later use. The input that is stored is not correctly filtered. As a consequence, the malicious data will appear to be part of the web site and run within the user’s browser under the privileges of the web application. \n\n A successful exploitation occurs when a user visits a page with a stored XSS.\nThe following phases relate to a typical stored XSS attack scenario: \n • Attacker stores malicious code into the vulnerable page \n • User authenticates in the application \n • User visits vulnerable page \n • Malicious code is executed by the user’s browser \n\n This vulnerability can be used to conduct a number of browser-based attacks including: \n • Hijacking another user’s browser \n • Capturing sensitive information viewed by application users \n • Pseudo defacement of the application \n • Port scanning of internal hosts \n • Directed delivery of browser-based exploits \n • Other malicious activities",
|
||||
"003": "The HTTP specification includes request methods other than the standard GET and POST requests. A standards compliant web server may respond to these alternative methods in ways not anticipated by developers. \n\n As the HTML standard does not support request methods other than GET or POST, we will need to craft custom HTTP requests to test the other methods. \n\n The full HTTP 1.1 specification defines the following valid HTTP request methods, or verbs: \n • OPTIONS \n • GET \n • HEAD \n • POST \n • PUT \n • DELETE \n • TRACE \n • CONNECT \n\n If enabled, the Web Distributed Authoring and Version (WebDAV) extensions permit several more HTTP methods: \n • PROPFIND \n • PROPPATCH \n • MKCOL \n • COPY \n • MOVE \n • LOCK \n • UNLOCK",
|
||||
"004": "Supplying multiple HTTP parameters with the same name may cause an application to interpret values in unanticipated ways. By exploiting these effects, an attacker may be able to bypass input validation, trigger application errors or modify internal variables values. As HTTP Parameter Pollution (in short HPP) affects a building block of all web technologies, server and client side attacks exist. \n\n Luckily, because the assignment of HTTP parameters is typically handled via the web application server, and not the application code itself, testing the response to parameter pollution should be standard across all pages and actions. \n However, as in-depth business logic knowledge is necessary, testing HPP requires manual testing. \n Automatic tools can only partially assist auditors as they tend to generate too many false positives. In addition, HPP can manifest itself in client-side and server-side components.",
|
||||
"005": "SQL injection attacks are a type of injection attack, in which SQL commands are injected into data-plane input in order to affect the execution of predefined SQL commands. \n\n The tester can supply crafted input trying to make the original SQL statement execute further actions of the testers’s choice. \n As an example the tester could change a statement to “$password = 1’ or ‘1’ = ‘1”, changing the logic of the SQL statement, modifying the WHERE clause adding a condition “or ‘1’ = ‘1” \n\n SQL Injection attacks can be divided into the following three classes: \n • Inband \n • Out-of-band \n • Inferential or Blind \n\n About the techniques to exploit SQL injection flaws there are five commons techniques. Also those techniques sometimes can be used in a combined way: \n • Union Operator \n • Boolean \n • Error based \n • Out-of-band \n • Time delay",
|
||||
"005_1": "Web based PL/SQL applications are enabled by the PL/SQL Gateway, which is is the component that translates web requests into database queries. Oracle has developed a number of software implementations. \n Products that use the PL/SQL Gateway include, but are not limited to, the Oracle HTTP Server, eBusiness Suite, Portal, HTMLDB, WebDB and Oracle Application Server. \n\n Essentially the PL/SQL Gateway simply acts as a proxy server taking the user’s web request and passes it on to the database server where it is executed. \n\n Step 1: \n The web server accepts a request from a web client and determines if it should be processed by the PL/SQL Gateway. \n\n Step 2: \n The PL/SQL Gateway processes the request by extracting the requested package name, procedure, and variables. \n\n Step 3: \n The requested package and procedure are wrapped in a block of anonymous PL/SQL, and sent to the database server. \n\n Step 4: \n The database server executes the procedure and sends the results back to the Gateway as HTML \n\n Step 5: \n The gateway sends the response, via the web server, back to the client. \n\n Understanding this point is important - the PL/SQL code does not exist on the web server but, rather, in the database server. \n This means that any weaknesses in the PL/SQL Gateway or any weaknesses in the PL/SQL application, when exploited, give an attacker direct access to the database server.",
|
||||
"005_2": "SQL Injection vulnerabilities occur whenever input is used in the construction of a SQL query without being adequately constrained or sanitized. \n MySQL server has a few particularities so that some exploits need to be specially customized for this application. \n\n When an SQL injection vulnerability is found in an application backed by a MySQL database, there are a number of attacks that could be performed depending on the MySQL version and user privileges on DBMS. \n\n MySQL comes with at least four versions which are used in production worldwide. Every version has a set of features proportional to version number: \n • From Version 4.0: UNION \n • From Version 4.1: Subqueries \n • From Version 5.0: Stored procedures, Stored functions and the view named INFORMATION_SCHEMA \n • From Version 5.0.2: Triggers \n\n It should be noted that for MySQL versions before 4.0.x, only Boolean or time-based Blind Injection attacks could be used, since the subquery functionality or UNION statements were not implemented.",
|
||||
"005_3": "SQL injection allows an attacker to access the SQL servers and execute SQL code under the privileges of the user used to connect to the database. SQL Injection techniques for Microsoft SQL Server utilize specific features. \n\n As explained in SQL injection, a SQL-injection exploit requires two things: an entry point and an exploit to enter. \n Any user-controlled parameter that gets processed by the application might be hiding a vulnerability. This includes: \n • Application parameters in query strings (e.g., GET requests) \n • Application parameters included as part of the body of a POST request \n • Browser-related information (e.g., user-agent, referrer) \n • Host-related information (e.g., host name, IP) \n • Session-related information (e.g., user ID, cookies) \n\n Some Microsoft SQL Server operators and commands are: \n • comment operator -- \n • query separator ; \n\n Useful stored procedures include: \n • xp_cmdshell \n • xp_regread \n • xp_regwrite \n • sp_configure \n • sp_ makewebtask \n • sp_sendmail",
|
||||
"005_4": "When a SQL Injection has been found, you need to carefully fingerprint the backend database engine. You can determine that the backend database engine is PostgreSQL by using the :: cast operator. \n In addition, the function version() can be used to grab the PostgreSQL banner. This will also show the underlying operating system type and version. \n\n SQL Injection techniques for PostgreSQL have the following characteristics: \n • PHP Connector allows multiple statements to be executed by using ; as a statement separator \n • SQL Statements can be truncated by appending the comment char: -- \n • LIMIT and OFFSET can be used in a SELECT statement to retrieve a portion of the result set generated by the query \n\n For blind SQL injection attacks, you should take into consideration the following built-in functions: \n • String Length - LENGTH(str) \n • Extract a substring from a given string - SUBSTR(str,index,offset) \n • String representation with no single quotes - CHR(101)||CHR(108)||CHR(111)",
|
||||
"005_5": "Microsoft Access can utilize specific features for SQL injection techniques. \n Unfortunately, MS Access doesn’t support typical operators that are traditionally used during SQL injection testing, including: \n• No comments characters\n• No stacked queries\n• No LIMIT operator\n• No SLEEP or BENCHMARK alike operators\n• and many others \n\n Still, there are also many other functions that can be used while testing SQL injection, including but not limited to: \n • ASC: Obtain the ASCII value of a character passed as input \n • CHR: Obtain the character of the ASCII value passed as input \n • LEN: Return the length of the string passed as parameter \n • IIF: Is the IF construct, e.g. IIF(1=1, ‘a’, ‘b’) return ‘a’ \n • MID: This function allows you to extract substring \n • TOP: This function allows you to specify the max. number of results \n • LAST: This function is used to select only the last row of a set \n\n Various system tables exist by default in MS Access that can be potentially used to obtain table names and columns. \n Unfortunately, in the default configuration of recent MS Access database releases, these tables are not accessible. Nevertheless, it is always worth trying: \n • MSysObjects \n • MSysACEs \n • MSysAccessXML",
|
||||
"005_6": "NoSQL databases provide looser consistency restrictions than traditional SQL databases. By requiring fewer relational constraints and consistency checks, NoSQL databases often offer performance and scaling benefits. \n But because these NoSQL injection attacks may execute within a procedural language , rather than in the declarative SQL language, the potential impacts are greater than traditional SQL injection. \n\n NoSQL database calls are written in the application’s programming language, a custom API call, or formatted according to a common convention (such as XML, JSON, LINQ, etc). \n\n Typically NoSQL injection attacks will execute where the attack string is parsed, evaluated, or concatenated into a NoSQL API call. \n Additional timing attacks may be relevant to the lack of concurrency checks within a NoSQL database. These are not covered under injection testing. \n\n There are now over 150 NoSQL databases available, but at the time of writing MongoDB is the most widely used NoSQL database. \n\n The MongoDB API expects BSON (Binary JSON) calls, and includes a secure BSON query assembly tool. However, according to MongoDB documentation - unserialized JSON and JavaScript expressions are permitted in several alternative query parameters. \n For example if an attacker were able to manipulate the data passed into the $where operator, that attacker could include arbitrary JavaScript to be evaluated as part of the MongoDB query.",
|
||||
"005_7": "ORM Injection is an attack using SQL Injection against an ORM generated data access object model. From the point of view of a tester, this attack is virtually identical to a SQL Injection attack. However, the injection vulnerability exists in code generated by the ORM tool.\n\nAn ORM is an Object Relational Mapping tool. \nIt is used to expedite object oriented development within the data access layer of software applications, including web applications. The benefits of using an ORM tool include quick generation of an object layer to communicate to a relational database, standardized code templates for these objects, and usually a set of safe functions to protect against SQL Injection attacks. ORM generated objects can use SQL or in some cases, a variant of SQL, to perform CRUD operations on a database.\n\nORM tools include Hibernate for Java, NHibernate for .NET, ActiveRecord for Ruby on Rails, EZPDO for PHP and many others.\n\nORM Injection vulnerabilities is identical to SQL Injection testing. In most cases, the vulnerability in the ORM layer is a result of customized code that does not properly validate input parameters. \nMost ORM tools provide safe functions to escape user input. However, if these functions are not used, and the developer uses custom functions that accept user input, it may be possible to execute a SQL injection attack.\n\nPatterns to look for in code include: \n• Input parameters concatenated with SQL strings",
|
||||
"005_8": "Client-side SQL injection occurs when an application implements the Web SQL Database technology and doesn’t properly validate the input nor parametrize its query variables. This database is manipulated by using JavaScript (JS) API calls, such as openDatabase() , which creates or opens an existing database.\n\nThe following test scenario will validate that proper input validation is conducted. If the implementation is vulnerable, the attacker can read, modify, or delete information stored within the database.\n\nIf the tested application implements the Web SQL DB, the following three calls will be used in the client-side core:\n• openDatabase() \n• transaction() \n• executeSQL()",
|
||||
"006": "The Lightweight Directory Access Protocol (LDAP) is used to store information about users, hosts, and many other objects. LDAP injection is a server side attack, which could allow sensitive information about users and hosts represented in an LDAP structure to be disclosed, modified, or inserted. This is done by manipulating input parameters afterwards passed to internal search, add, and modify functions. \n A web application could use LDAP in order to let users authenticate or search other users’ information inside a corporate structure. \n\n The goal of LDAP injection attacks is to inject LDAP search filters metacharacters in a query which will be executed by the application.\n [Rfc2254] defines a grammar on how to build a search filter on LDAPv3 and extends [Rfc1960] (LDAPv2). \nAn LDAP search filter is constructed in Polish notation, also known as [prefix notation]. \n\n A successful exploitation of an LDAP injection vulnerability could allow the tester to: \n • Access unauthorized content \n • Evade application restrictions \n • Gather unauthorized informations \n • Add or modify Objects inside LDAP tree structure",
|
||||
"007": "XML Injection testing is when a tester tries to inject an XML doc to the application. If the XML parser fails to contextually validate data, then the test will yield a positive result. \n\n Step 1: \n In order to test an application for the presence of a XML Injection vulnerability consists of trying to insert XML metacharacters. \n\n XML metacharacters are: \n • Single quote: ‘ \n • Double quote: “ \n • Angular parentheses: > and < \n • Comment tag: <!--/--> \n • Ampersand: & \n • CDATA section delimiters: <![CDATA[ / ]]> \n\n Another test is related to CDATA tag. Suppose that the XML document is processed to generate an HTML page. In this case, the CDATA section delimiters may be simply eliminated, without further inspecting their contents. Then, it is possible to inject HTML tags, which will be included in the generated page, completely bypassing existing sanitization routines. \n\n Step 2: \n Once the first step is accomplished, the tester will have some information about the structure of the XML document. Then, it is possible to try to inject XML data and tags (Tag Injection).",
|
||||
"008": "Web servers usually give developers the ability to add small pieces of dynamic code inside static HTML pages. This feature is incarnated by the Server-Side Includes (SSI). \nIn SSI injection testing, we test if it is possible to inject into the application data that will be interpreted by SSI mechanisms. A successful exploitation of this vulnerability allows an attacker to inject code into HTML pages or even perform remote code execution. \n\n With regard to SSI injection, the attacker could provide input that, if inserted by the application (or maybe directly by the server) into a dynamically generated page, would be parsed as one or more SSI directives. \n\n Step 1: \n What we need find is if the web server actually supports SSI directives. To find out we just need to discover which kind of web server is running on our target. \n Hint: If the site contains .shtml files, then SSI are probably supported, as this extension is used to identify pages containing these directives. \n\n Step 2: \n The next step consists of determining if an SSI injection attack is actually possible and, if so, what are the input points that we can use to inject our malicious code. \n We need to find every page where the user is allowed to submit some kind of input, and verify whether the application is correctly validating the submitted input. \n If sanitization is insufficient, we need to test if we can provide data that is going to be displayed unmodified. \n Besides common user-supplied data, input vectors that should always be considered are HTTP request headers and cookies content. \n\n Step 3: \n Once we have a list of potential injection points, we can check how the input is handled, what kind of filtering is performed, what characters the application is not letting through, and how many types of encoding are taken into account.",
|
||||
"009": "Web applications heavily use databases to store and access the data they need for their operations. \n Just like relational databases are accessed via SQL language, XML databases use XPath as their standard query language. \n\n XPath is a language that has been designed and developed primarily to address parts of an XML document. In XPath injection testing, we test if it is possible to inject XPath syntax into a request interpreted by the application, allowing an attacker to execute user-controlled XPath queries. \n XPath is even more powerful than standard SQL, as its whole power is already present in its specifications, whereas a large number of the techniques that can be used in a SQL Injection attack depend on the characteristics of the SQL dialect used by the target database. \n\n The XPath attack pattern is very similar to the usual SQL Injection and as in a common SQL Injection attack, with XPath injection, the first step is to insert a single quote (‘) in the field to be tested, introducing a syntax error in the query, and to check whether the application returns an error message.",
|
||||
"010": "This threat affects all applications that communicate with mail servers (IMAP/SMTP), generally webmail applications. The aim of this test is to verify the capacity to inject arbitrary IMAP/SMTP commands into the mail servers, due to input data not being properly sanitized. \n\n An IMAP/SMTP Injection makes it possible to access a mail server which otherwise would not be directly accessible from the Internet. In some cases, these internal systems do not have the same level of infrastructure security and hardening that is applied to the front-end web servers.Therefore, mail server results may be more vulnerable to attacks by end users. \n\n The standard attack patterns are: \n • Identifying vulnerable parameters \n • Understanding the data flow and deployment structure of the client \n • IMAP/SMTP command injection \n\n This last stage has two possible outcomes: \n\n Outcome 1: \n The injection is possible in an unauthenticated state: The affected functionality does not require the user to be authenticated. \n The injected (IMAP) commands available are limited to: \nCAPABILITY, NOOP, AUTHENTICATE, LOGIN, and LOGOUT. \n\n Outcome 2: \n The injection is only possible in an authenticated state: the successful exploitation requires the user to be fully authenticated before testing can continue. \n\n In any case, the typical structure of an IMAP/SMTP Injection is as follows: \n • Header: ending of the expected command; \n • Body: injection of the new command; \n • Footer: beginning of the expected command.",
|
||||
"011": "In Code Injection testing, a tester submits input that is processed by the web server as dynamic code or as an included file. These tests can target various server-side scripting engines, e.g.., ASP or PHP. Proper input validation and secure coding practices need to be employed to protect against these attacks. \n\n Testing for PHP Injection vulnerabilities \n Using the querystring, the tester can inject code to be processed as part of the included file. The malicious URL is accepted as a parameter for the PHP page, which will later use the value in an included file. \n\n Testing for ASP Code Injection vulnerabilities \n Examine ASP code for user input used in execution functions.\nCan the user enter commands into the Data input field?",
|
||||
"011_1": "The File Inclusion vulnerability allows an attacker to include a file, usually exploiting a “dynamic file inclusion” mechanisms implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation. \n\n This can lead to something as outputting the contents of the file, but depending on the severity, it can also lead to: \n • Code execution on the web server \n • Code execution on the client-side such as JavaScript which can lead to other attacks such as cross site scripting (XSS) \n • Denial of Service (DoS) \n • Sensitive Information Disclosure \n\n Local File Inclusion (also known as LFI) is the process of including files, that are already locally present on the server, through the exploiting of vulnerable inclusion procedures. \n Since LFI occurs when paths passed to “include” statements are not properly sanitized, in a blackbox testing approach, we should look for scripts which take filenames as parameters.",
|
||||
"011_2": "The File Inclusion vulnerability allows an attacker to include a file, usually exploiting a “dynamic file inclusion” mechanisms implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation. \n\n This can lead to something as outputting the contents of the file, but depending on the severity, it can also lead to: \n • Code execution on the web server \n • Code execution on the client-side such as JavaScript which can lead to other attacks such as cross site scripting (XSS) \n • Denial of Service (DoS) \n • Sensitive Information Disclosure \n\n Remote File Inclusion (also known as RFI) is the process of including remote files through the exploiting of vulnerable inclusion procedures. \n\n Since RFI occurs when paths passed to “include” statements are not properly sanitized, in a blackbox testing approach, we should look for scripts which take filenames as parameters.",
|
||||
"012": "OS command injection is a technique used via a web interface in order to execute OS commands on a web server. The user supplies operating system commands through a web interface in order to execute OS commands. Any web interface that is not properly sanitized s subject to this exploit. \n\n When viewing a file in a web application, the file name is often shown in the URL. Perl allows piping data from a process into an open statement. The user can simply append the Pipe symbol “|” onto the end of the file name. \n Appending a semicolon to the end of a URL for a .PHP page followed by an operating system command, will execute the command. %3B is url encoded and decodes to semicolon.",
|
||||
"013": "A format string is a null-terminated character sequence that also contains conversion specifiers interpreted or converted at runtime. If server-side code concatenates a user’s input with a format string, an attacker can append additional conversion specifiers to cause a runtime error, information disclosure, or buffer overflow. \n\nAssess whether injecting format string conversion specifiers into user-controlled fields causes undesired behaviour from the application.\n\nThe worst case for format strings vulnerabilities occur in languages that don’t check arguments and also include a %n specifier that writes to memory. These functions, if exploited by an attacker modifying a format string, could cause information disclosure and code execution:\n• C and C++ printf and similar methods fprintf, sprintf, snprintf \n• Perl printf and sprintf\n\nThese format string functions cannot write to memory, but attackers can still cause information disclosure by changing format strings to output values the developers did not intend to send.\nThe following format string functions can cause runtime errors if the attacker adds conversion specifiers: \n• Java String.format and PrintStream.format\n• PHP printf\n\nTests include analysis of the code and injecting conversion specifiers as user input to the application under test.",
|
||||
"014": "Also often refered to as persistent attacks, incubated testing is a complex testing method that needs more than one data validation vulnerability to work. \n Incubated vulnerabilities are typically used to conduct “watering hole” attacks against users of legitimate web applications. \n\n Incubated vulnerabilities have the following characteristics: \n\n Firstly: \n The attack vector needs to be persisted in the first place, it needs to be stored in the persistence layer, and this would only occur if weak data validation was present or the data arrived into the system via another channel such as an admin console or directly via a backend batch process. \n\n Secondly: \n Once the attack vector was “recalled” the vector would need to be executed successfully. For example, an incubated XSS attack would require weak output validation so the script would be delivered to the client in its executable form. \n\n Exploitation of some vulnerabilities, or even functional features of a web application, will allow an attacker to plant a piece of data that will later be retrieved. \n In a penetration test, incubated attacks can be used to assess the criticality of certain bugs that usually will be used to target a large number of victims at the same time. \n\n This type of asynchronous attack covers a great spectrum of attack vectors, among them the following: \n • File upload components in a web application \n • Cross-site scripting issues in public forums posts \n • SQL/XPATH Injection allowing the attacker to upload content to a database \n • Misconfigured servers allowing installation of packages or components \n\n Step 1: \n Verify the content type allowed to upload to the web application and the resultant URL for the uploaded file. \n\n Step 2: \n Upload a file that will exploit a component in the local user workstation when viewed or downloaded by the user. \n\n Step 3: \n Send your victim an email or other kind of alert in order to lead him/her to browse the page. \n\n The expected result is the exploit will be triggered when the user browses the resultant page or downloads and executes the file from the trusted site.",
|
||||
"015": "There are two different attacks that target specific HTTP headers:\n• HTTP splitting\n• HTTP smuggling \n\n The first attack exploits a lack of input sanitization which allows an intruder to insert CR and LF characters into the headers of the application response and to ‘split’ that answer into two different HTTP messages. \n The goal of the attack can vary from a cache poisoning to cross site scripting. \n\n In the second attack, the attacker exploits the fact that some specially crafted HTTP messages can be parsed and interpreted in different ways depending on the agent that receives them.\nHTTP smuggling requires some level of knowledge about the different agents that are handling the HTTP messages (web server, proxy, firewall). \n\n HTTP Splitting \n Some web applications use part of the user input to generate the values of some headers of their responses. The most straightforward example is provided by redirections in which the target URL depends on some user-submitted value. \n The headers that are the most likely candidates for this attack are:\n• Location\n• Set-Cookie \n\n HTTP Smuggling\n This leverages the different ways that a particularly crafted HTTP message can be parsed and interpreted by different agents (browsers, web caches, application firewalls).",
|
||||
"016": "This section describes how to monitor all incoming/outgoing HTTP requests on both client-side or server-side. The purpose of this testing is to verify if there is unnecessary or suspicious HTTP request sending in the background. \n\nMost of Web security testing tools (i.e. AppScan, BurpSuite, ZAP) act as HTTP Proxy. This will require changes of proxy on client-side application or browser. The testing techniques listed below is primary focused on how we can monitor HTTP requests without changes of client-side which will be more close to production usage scenario.\n\nTest Objectives \n• Monitor all incoming and outgoing HTTP requests to the Web Server to inspect any suspicious requests. \n• Monitor HTTP traffic without changes of end user Browser proxy or client-side application.\n\nHow to Test\nThere is situation that we would like to monitor all HTTP incoming requests on web server but we can’t change configuration on the browser or application client-side. In this scenario, we can setup a reverse proxy on web server end to monitor all incoming/outgoing requests on web server:\n• For windows platform, Fiddler is recommended.\n• For Linux platform, Charles Web Debugging Proxy may be used.\n\nThe testing steps: \n1. Install Fiddler or Charles on Web Server \n2. Configure the Fiddler or Charles as Reverse Proxy \n3. Capture the HTTP traffic \n4. Inspect HTTP traffic \n5. Modify HTTP requests and replay the modified requests for testing",
|
||||
"017": "A web server commonly hosts several web applications on the same IP address, referring to each application via the virtual host. In an incoming HTTP request, web servers often dispatch the request to the target virtual host based on the value supplied in the Host header. Without proper validation of the header value, the attacker can supply invalid input to cause the web server to:\n• dispatch requests to the first virtual host on the list \n• cause a redirect to an attacker-controlled domain \n• perform web cache poisoning \n• manipulate password reset functionality \n\nTest Objectives \n• Assess if the Host header is being parsed dynamically in the application. \n• Bypass security controls that rely on the header\n\nHow to Test\nInitial testing is as simple as supplying another domain (i.e. attacker.com ) into the Host header field. It is how the web server processes the header value that dictates the impact. The attack is valid when the web server processes the input to send the request to an attacker-controlled host that resides at the supplied domain, and not to an internal virtual host that resides on the web server.\n\nFurther Attacks\n• X-Forwarded Host Header Bypass\n• Web Cache Poisoning\n• Password Reset Poisoning",
|
||||
"018": "Web applications commonly use server-side templating technologies (Jinja2, Twig, FreeMaker, etc.) to generate dynamic HTML responses. Server-side Template Injection vulnerabilities (SSTI) occur when user input is embedded in a template in an unsafe manner and results in remote code execution on the server. \n\nAny features that support advanced user-supplied markup may be vulnerable to SSTI including wiki-pages, reviews, marketing applications, CMS systems etc. Some template engines employ various mechanisms (eg. sandbox, allow listing, etc.) to protect against SSTI.\n\nTest Objectives \n• Detect template injection vulnerability points. \n• Identify the templating engine. \n• Build the exploit.\n\nHow to Test \n• Identify Template Injection Vulnerability\n• Identify the Templating Engine\n• Build the RCE Exploit",
|
||||
"019": "Web applications often interact with internal or external resources. While you may expect that only the intended resource will be handling the data you send, improperly handled data may create a situation where injection attacks are possible. One type of injection attack is called Server-side Request Forgery (SSRF). \n\nA successful SSRF attack can grant the attacker access to restricted actions, internal services, or internal files within the application or the organization. In some cases, it can even lead to Remote Code Execution (RCE).\n\nTest Objectives \n• Identify SSRF injection points. \n• Test if the injection points are exploitable. \n• Asses the severity of the vulnerability.\n\nHow to Test\n• Load the Contents of a File\n• Access a Restricted Page\n• Fetch a Local File\n\nCommon Filter Bypass\nSometimes the application allows input that matches a certain expression, like a domain. That can be circumvented if the URL schema parser is not properly implemented, resulting in attacks similar to semantic attacks.\n• Using the @ character to separate between the userinfo and the host: https://expected-domain@attackerdomain \n• URL fragmentation with the # character: https://attacker-domain#expected-domain \n• URL encoding \n• Fuzzing \n• Combinations of all of the above"
|
||||
},
|
||||
"err": {
|
||||
"001": "Often, during a penetration test on web applications, we come up against many error codes generated from applications or web servers.\n It’s possible to cause these errors to be displayed by using a particular requests, either specially crafted with tools or created manually. These codes are very useful to penetration testers during their activities, because they reveal a lot of information about databases, bugs, and other technological components directly linked with web applications. \n\n A good collection of error information can facilitate assessment efficiency by decreasing the overall time taken to perform the penetration test. \n Attackers sometimes use search engines to locate errors that disclose information. Searches can be performed to find any erroneous sites as random victims, or it is possible to search for errors in a specific site using the search engine filtering tools. \n\n Below are some areas listed that could return detailed error messages to the user. Each of the areas has specific information about the operating system, application version, etc. \n • Web Server Errors (HTTP Responses) \n • Application Server Errors (Framework messages) \n • Database Errors (Database System messages)",
|
||||
"002": "Stack traces are not vulnerabilities by themselves, but they often reveal information that is interesting to an attacker. Attackers attempt to generate these stack traces by tampering with the input to the web application with malformed HTTP requests and other input data. \n\n If the application responds with stack traces that are not managed it could reveal information useful to attackers. This information could then be used in further attacks. \n\n There are a variety of techniques that will cause exception messages to be sent in an HTTP response. Note that in most cases this will be an HTML page, but exceptions can be sent as part of SOAP or REST responses too. \nSome tests to try include: \n • invalid input \n • input that contains non alphanumeric chars or query syntax \n • empty inputs \n • inputs that are too long \n • access to internal pages without authentication \n • bypassing application flow \n\n All the above tests could lead to application errors that may contain stack traces. It is recommended to use a fuzzer in addition to any manual testing. \n\n When the SSL/TLS service is present it is good but it increments the attack surface and the following vulnerabilities exist: \n • SSL/TLS protocols, ciphers, keys and renegotiation must be properly configured \n • Certificate validity must be ensured"
|
||||
},
|
||||
"crypst": {
|
||||
"001": "Sensitive data must be protected when it is transmitted through the network. \nAs a rule of thumb, if data must be protected when it is stored, it must be protected also during transmission. \n\n Various types of information which must be protected can be also transmitted in clear text. It is possible to check if this information is transmitted over HTTP instead of HTTPS. \n\n HTTP is a clear-text protocol and it is normally secured via an SSL/TLS tunnel, resulting in HTTPS traffic. Servers are authenticated using digital certificates and it is also possible to use client certificate for mutual authentication. \n Even if high grade ciphers are today supported and normally used, some misconfiguration in the server can be used to force the use of a weak cipher - or at worst no encryption - permitting to an attacker to gain access to the supposed secure communication channel. \n\n Common Issues: \n When the SSL/TLS service is present it is good but it increments the attack surface and the following vulnerabilities exist: \n • SSL/TLS protocols, ciphers, keys and renegotiation must be properly configured \n • Certificate validity must be ensured \n • Software exposed must be updated due to possibility of known vulnerabilities \n • Usage of Secure flag for Session Cookies \n • Usage of HTTP Strict Transport Security (HSTS) \n • The presence of HTTP and HTTPS both, which can be used to intercept traffic \n • The presence of mixed HTTPS and HTTP content in the same page, which can be used to Leak information \n\n Testing for sensitive data transmitted in clear-text \n A typical example is the usage of Basic Authentication over HTTP because with Basic Authentication, after log in, credentials are encoded - and not encrypted - into HTTP Headers. \n\n Testing for Weak SSL/TLS Ciphers/Protocols/Keys vulnerabilities \n The large number of available cipher suites and quick progress in cryptanalysis makes testing an SSL server a non-trivial task. At the time of writing these criteria are widely recognized a checklist: \n • Weak ciphers must not be used (e.g. less than 128 bits) \n • No NULL ciphers suite, due to no encryption used \n • Weak protocols must be disabled (e.g. SSLv2 must be disabled) \n • Renegotiation must be properly configured (e.g. Insecure Renegotiation must be disabled) \n • No Export (EXP) level cipher suites, due to can be easly broken \n • X.509 certificates key length must be strong \n • X.509 certificates must be signed only with secure hashing algoritms \n • Keys must be generated with proper entropy \n • Secure Renegotiation should be enabled. \n • MD5 should not be used, due to known collision attacks \n • RC4 should not be used, due to crypto-analytical attacks \n • Server should be protected from BEAST Attack \n • Server should be protected from CRIME attack, TLS compression must be disabled \n • Server should support Forward Secrecy",
|
||||
"002": "A padding oracle is a function of an application which decrypts encrypted data provided by the client, e.g. internal session state stored on the client, and leaks the state of the validity of the padding after decryption. \n\n The existence of a padding oracle allows an attacker to decrypt encrypted data and encrypt arbitrary data without knowledge of the key used for these cryptographic operations. \n\n Block ciphers encrypt data only in blocks of certain sizes. Block sizes used by common ciphers are 8 and 16 bytes. Data where the size doesn’t match a multiple of the block size of the used cipher has to be padded in a specific manner so the decryptor is able to strip the padding. \n\n The padding oracle attack enables an attacker to decrypt encrypted data without knowledge of the encryption key and used cipher by sending skillful manipulated cipher texts to the padding oracle and observing of the results returned by it. This causes loss of confidentiality of the encrypted data. \n A padding oracle attack also enables an attacker to encrypt arbitrary plain texts without knowledge of the used key and cipher. \n\n First the possible input points for padding oracles must be identified. Generally the following conditions must be met: \n\n Condition 1: \n The data is encrypted. Good candidates are values which appear to be random. \n\n Condition 2: \n A block cipher is used. The length of the decoded (e.g. Base64) cipher text is a multiple of common cipher block sizes like 8 or 16 bytes. Different cipher texts share a common divisor in the length. \n\n If such an input value candidate is identified, the behavior of the application to bit-wise tampering of the encrypted value should be verified. \n The tests and the base value should at least cause three different states while and after decryption: \n • Cipher text gets decrypted, resulting data is correct \n • Cipher text gets decrypted, resulting data is garbled and causes some exception or error handling in the application logic \n • Cipher text decryption fails due to padding errors \n\n Search especially for exceptions and messages which state that something is wrong with the padding. If the three different states described above are observable implicitly (different error messages, timing side-channels), there is a high probability that there is a padding oracle present at this point. Examples: \n • ASP.NET throws “System.Security.Cryptography.Cryptographic Exception: Padding is invalid and cannot be removed.” \n • In Java a javax.crypto.BadPaddingException is thrown in this case \n • Decryption errors or similar can be possible padding oracles",
|
||||
"003": "Sensitive data must be protected when it is transmitted through the network. If data is transmitted over HTTPS or encrypted in another way the protection mechanism must not have limitations or vulnerabilities. \n\n As a rule of thumb if data must be protected when it is stored, this data must also be protected during transmission. \n Some examples for sensitive data are: \n • Information used in authentication (e.g. Credentials, PINs, Tokens, Cookies…) \n • Information protected by laws, regulations or specific organizational policy (e.g. Credit Cards, Customers data) \n\n Various types of information that must be protected, could be transmitted by the application in clear text. It is possible to check if this information is transmitted over HTTP instead of HTTPS, or whether weak cyphers are used. \n\n 1. Basic Authentication over HTTP \n A typical example is the usage of Basic Authentication over HTTP. When using Basic Authentication, user credentials are encoded rather than encrypted, and are sent as HTTP headers. \n\n 2. Form-Based Authentication Performed over HTTP \n Another typical example is authentication forms which transmit user authentication credentials over HTTP. It is possible to see this issue by examining the HTTP traffic with an interception proxy. \n\n 3. Cookie Containing Session ID Sent over HTTP \n The Session ID Cookie must be transmitted over protected channels. If the cookie does not have the secure flag set it is permitted for the application to transmit it unencrypted.",
|
||||
"004": "Incorrect uses of encryption algorithms may result in sensitive data exposure, key leakage, broken authentication, insecure session, and spoofing attacks. There are some encryption or hash algorithms known to be weak and are not suggested for use such as MD5 and RC4. \n\nIn addition to the right choices of secure encryption or hash algorithms, the right uses of parameters also matter for the security level. For example, ECB (Electronic Code Book) mode is not suggested for use in asymmetric encryption.\n\nTest Objectives \n• Provide a guideline for the identification weak encryption or hashing uses and implementations.\n\nBasic Security Checklist\n• When using AES128 or AES256, the IV (Initialization Vector) must be random and unpredictable.\n• For asymmetric encryption, use Elliptic Curve Cryptography (ECC) with a secure curve like Curve25519 preferred.\n• When uses of RSA in signature, PSS padding is recommended.\n• Weak hash/encryption algorithms should not be used such MD5, RC4, DES, Blowfish, SHA1.\n• Password Hashing: PBKDF2, Scrypt, Bcrypt\n• Uses of SSH, CBC mode should not be used.\n• When symmetric encryption algorithm is used, ECB (Electronic Code Book) mode should not be used.\n• When PBKDF2 is used to hash password, the parameter of iteration is recommended to be over 10000."
|
||||
},
|
||||
"buslogic": {
|
||||
"001": "The application must ensure that only logically valid data can be entered at the front end as well as directly to the server side of an application of system. Only verifying data locally may leave applications vulnerable to server injections through proxies or at handoffs with other systems. This is different from simply performing Boundary Value Analysis (BVA) in that it is more difficult and in most cases cannot be simply verified at the entry point, but usually requires checking some other system. \n\n Vulnerabilities related to business data validation is unique in that they are application specific and different from the vulnerabilities related to forging requests in that they are more concerned about logical data as opposed to simply breaking the business logic workflow. \n\n The front end and the back end of the application should be verifying and validating that the data it has, is using and is passing along is logically valid. Even if the user provides valid data to an application the business logic may make the application behave differently depending on data or circumstances. \n\n Generic Test Method \n • Review the project documentation and use exploratory testing looking for data entry points or hand off points between systems or software \n • Once found try to insert logically invalid data into the application/system \n\n Specific Testing Method \n • Perform front-end GUI Functional Valid testing on the application to ensure that the only “valid” values are accepted. \n • Using an intercepting proxy observe the HTTP POST/GET looking for places that variables such as cost and quality are passed. Specifically, look for “hand-offs” between application/systems that may be possible injection of tamper points. \n • Once variables are found start interrogating the field with logically “invalid” data, such as social security numbers or unique identifiers that do not exist or that do not fit the business logic. \n This testing verifies that the server functions properly and does not accept logically invalid data them.",
|
||||
"002": "Forging requests is a method that attackers use to circumvent the front end GUI application to directly submit information for back end processing. The goal of the attacker is to send HTTP POST/GET requests through an intercepting proxy with data values that is not supported, guarded against or expected by the applications business logic. \n\n Vulnerabilities related to the ability to forge requests is unique to each application and different from business logic data validation in that it s focus is on breaking the business logic workflow. \n\n The application must be smart enough and designed with business logic that will prevent attackers from predicting and manipulating parameters to subvert programmatic or business logic flow, or exploiting hidden/undocumented functionality such as debugging. \n\n Generic Testing Method \n • Review the project documentation and use exploratory testing looking for guessable, predictable or hidden functionality of fields. \n • Once found try to insert logically valid data into the application/system allowing the user go through the application/system against the normal busineess logic workflow. \n\n Specific Testing Method 1 \n • Using an intercepting proxy observe the HTTP POST/GET looking for some indication that values are incrementing at a regular interval or are easily guessable. \n • If it is found that some value is guessable this value may be\nchanged and one may gain unexpected visibility. \n\n Specific Testing Method 2 \n • Using an intercepting proxy observe the HTTP POST/GET looking for some indication of hidden features such as debug that can be switched on or activated. \n • If any are found try to guess and change these values to get a different application response or behavior.",
|
||||
"003": "Many applications are designed to display different fields depending on the user of situation by leaving some inputs hidden.\nHowever, in many cases it is possible to submit values hidden field values to the server using a proxy. In these cases the server side controls must be smart enough to perform relational or server side edits to ensure that the proper data is allowed to the server based on user and application specific business logic. \n\n Additionally, the application must not depend on non-editable controls, drop-down menus or hidden fields for business logic processing because these fields remain non-editable only in the context of the browsers. Users may be able to edit their values using proxy editor tools and try to manipulate business logic. \n\nBusiness logic integrity check vulnerabilities is unique in that these misuse cases are application specific and if users are able to make changes one should only be able to write or update/edit specific artifacts at specific times per the business process logic.\nThe application must be smart enough to check for relational edits and not allow users to submit information directly to the server that is not valid, trusted because it came from a non-editable controls or the user is not authorized to submit through the front end. \n\n Generic Testing Method \n • Review the project documentation and use exploratory testing looking for parts of the application/system (i.e. input fields, databases or logs) that move, store or handle data/information. \n • For each identified component determine what type of data/information is logically acceptable and what types the application/system should guard against. Also, consider who according to the business logic is allowed to insert, update and delete data/information and in each component. \n • Attempt to insert, update or edit delete the data/information values with invalid data/information into each component (i.e. input, database, or log) by users that should not be allowed per the business logic workflow. \n\n Specific Testing Method 1 \n • Using a proxy capture and HTTP traffic looking for hidden fields. \n • If a hidden field is found see how these fields compare with the GUI application and start interrogating this value through the proxy by submitting different data values trying to circumvent the business process and manipulate values you were not intended to have access to. \n\n Specific Testing Method 2 \n • Using a proxy capture and HTTP traffic looking a place to insert information into areas of the application that are non-editable. \n • If it is found see how these fields compare with the GUI application and start interrogating this value through the proxy by submitting different data values trying to circumvent the business process and manipulate values you were not intended to have access to. \n\n Specific Testing Method 3 \n • List components of the application or system that could be edited, for example logs or databases. \n • For each component identified, try to read, edit or remove its information. For example log files should be identified and Testers should try to manipulate the data/information being collected.",
|
||||
"004": "It is possible that attackers can gather information on an application by monitoring the time it takes to complete a task or give a respond. \n Additionally, attackers may be able to manipulate and break designed business process flows by simply keeping active sessions open and not submitting their transactions in the “expected” time frame. \n\n Process timing logic vulnerabilities is unique in that these manual misuse cases should be created considering execution and transaction timing that are application/system specific. \nProcessing timing may give/leak information on what is being done in the application/system background processes. If an application allows users to guess what the particulate next outcome will be by processing time variations, users will be able to adjust accordingly and change behavior. \n\n How to Test #1 \n Review the project documentation and use exploratory testing looking for application/system functionality that may be impacted by time. Such as execution time or actions that help users predict a future outcome or allow one to circumvent any part of the business logic or workflow. \n For example, not completing transactions in an expected time. \n\n How to Test #2 \n Develop and execute the mis-use cases ensuring that attackers can not gain an advantage based on any timing.",
|
||||
"005": "Many of the problems that applications are solving require limits to the number of times a function can be used or action can be executed. Applications must be “smart enough” to not allow the user to exceed their limit on the use of these functions since in many cases each time the function is used the user may gain some type of benefit that must be accounted for to properly compensate the owner. \n\n Vulnerabilities related to testing for the function limits are application specific and misuse cases must be created that strive to exercise parts of the application/functions/ or actions more than the allowable number of times.\nAttackers may be able to circumvent the business logic and execute a function more times than “allowable” exploiting the application for personal gain. \n\n How to Test #1 \n Review the project documentation and use exploratory testing looking for functions or features in the application or system that should not be executed more that a single time or specified number of times during the business logic workflow. \n\n How to Test #2 \n For each of the functions and features found that should only be executed a single time or specified number of times during the business logic workflow, develop abuse/misuse cases that may allow a user to execute more than the allowable number of times. \n For example, can a user navigate back and forth through the pages multiple times executing a function that should only execute once or can a user load and unload shopping carts allowing for additional discounts.",
|
||||
"006": "Workflow vulnerabilities involve any type of vulnerability that allows the attacker to misuse an application/system in a way that will allow them to circumvent (not follow) the designed/intended workflow. \n\n “A workflow consists of a sequence of connected steps where each step follows without delay or gap and ends just before the subsequent step may begin. Workflow may be seen as any abstraction of real work.” \n\n The application’s business logic must require that the user complete specific steps in the correct/specific order and if the workflow is terminated without correctly completing, all actions and spawned actions are “rolled back” or canceled. \n\n Generic Testing Method \n • Review the project documentation and use exploratory testing looking for methods to skip or go to steps in the application process in a different order from the designed/intended business logic flow. \n • For each method develop a misuse case and try to circumvent or perform an action that is “not acceptable” per the the business logic workflow. \n\n Testing Method 1 \n • Start a transaction going through the application past the points that triggers credits/points to the users account. \n • Cancel out of the transaction or reduce the final tender so that the point values should be decreased and check the points/credit system to ensure that the proper points/credits were recorded. \n\n Testing Method 2 \n • On a content management or bulletin board system enter and save valid initial text or values. \n • Then try to append, edit and remove data that would leave the existing data in an invalid state or with invalid values to ensure that the user is not allowed to save the incorrect information.\n Some “invalid” data or information may be specific words (profanity) or specific topics (such as political issues).",
|
||||
"007": "The misuse and invalid use of of valid functionality can identify attacks attempting to enumerate the web application, identify weaknesses, and exploit vulnerabilities. Tests should be undertaken to determine whether there are application-layer defensive mechanisms in place to protect the application. \n\n The lack of active defenses allows an attacker to hunt for vulnerabilities without any recourse. The application’s owner will thus not know their application is under attack. \n\n This test is unusual in that the result can be drawn from all the other tests performed against the web application. \n While performing all the other tests, take note of measures that might indicate the application has in-built self-defense: \n • Changed responses \n • Blocked requests \n • Actions that log a user out or lock their account \n\n These may only be localised. Common localized (per function) defenses are: \n • Rejecting input containing certain characters \n • Locking out an account temporarily after a number of authentication failures \n\n Localized security controls are not sufficient. There are often no defenses against general mis-use such as: \n • Forced browsing \n • Bypassing presentation layer input validation\n • Multiple access control errors\n • Additional, duplicated or missing parameter names\n • Multiple input validation or business logic verification failures\n • Structured data (e.g. JSPN, XML) of an invalid format is received\n • Blatant cross-site scripting or SQL injection payloads are received\n • Utilising the application faster than would be possible\n • Change in continental geo-location of a user\n • Change of user agent \n • Accessing a multi-stage business process in the wrong order\n • Large number of, or high rate of use of, application-specific functionality \n\n Not all the above need to be monitored by the application, but there is a problem if none of them are. By testing the web application, doing the above type of actions, was any response taken against the tester? \n If not, the tester should report that the application appears to have no application-wide active defenses against misuse.",
|
||||
"008": "Many application’s business processes allow for the upload and manipulation of data that is submitted via files. \n The risk in that by allowing users to upload files, attackers may submit an unexpected file type that that could be executed and adversely impact the application or system through attacks that may deface the web site, perform remote commands, browse the system files, browse the local resources, attack other servers, or exploit the local vulnerabilities, just to name a few. \n\n Vulnerabilities related to the upload of unexpected file types is unique in that the upload should quickly reject a file if it does not have a specific extension. Additionally, this is different from uploading malicious files in that in most cases an incorrect file may be detrimental to the saved data. \n\n Generic Testing Method \n • Review the project documentation and perform some exploratory testing looking for file types that should be “unsupported” by the application/system. \n • Try to upload these “unsupported” files an verify that it are properly rejected. \n • If multiple files can be uploaded at once, there must be tests in place to verify that each file is properly evaluated. \n\n Specific Testing Method \n • Study the applications logical requirements \n • Prepare a library of files that are “not approved” for upload that may contain files such as: jsp, exe, or html files containing script. \n • In the application navigate to the file submission or upload mechanism. \n • Submit the “not approved” file for upload and verify that they are properly prevented from uploading.",
|
||||
"009": "Many application’s business processes allow for the upload of data/information. \n To reduce the risk we may only accept certain file extensions, but attackers are able to encapsulate malicious code into inert file types. \n\n Vulnerabilities related to the uploading of malicious files is unique in that these “malicious” files can easily be rejected through including business logic that will scan files during the upload process and reject those perceived as malicious.\nAdditionally, this is different from uploading unexpected files in that while the file type may be accepted the file may still be malicious to the system. \n\n General Testing Method \n • Review the project documentation and use exploratory testing looking at the application/system to identify what constitutes and “malicious” file in your environment. \n • Develop or acquire a known “malicious” file. \n • Try to upload the malicious file to the application/system and verify that it is correctly rejected. \n • If multiple files can be uploaded at once, there must be tests in place to verify that each file is properly evaluated. \n\n Specific Testing Method 1 \n • Using the Metasploit payload generation functionality generates a shellcode as a Windows executable using the Metasploit “msfpayload” command. \n • Submit the executable via the application’s upload functionality and see if it is accepted or properly rejected. \n\n Specific Testing Method 2 \n • Develop or create a file that should fail the application malware detection process. \n (there are many available on the Internet such as ducklin.htm or ducklin-html.htm) \n • Submit the executable via the application’s upload functionality and see if it is accepted or properly rejected. \n\n Specific Testing Method 3 \n • Set up the intercepting proxy to capture the “valid” request for an accepted file. \n • Send an “invalid” request through with a valid/acceptable file extension and see if the request is accepted or properly rejected."
|
||||
},
|
||||
"client": {
|
||||
"001": "DOM-based Cross-Site Scripting is the de-facto name for XSS bugs which are the result of active browser-side content on a page, typically JavaScript, obtaining user input and then doing something unsafe with it which leads to execution of injected code. \n\nThe DOM, or Document Object Model, is the structural format used to represent documents in a browser. The DOM enables dynamic scripts such as JavaScript to reference components of the document such as a form field or a session cookie. \n A DOM-based XSS vulnerability may occur when active content, such as a JavaScript function, is modified by a specially crafted request such that a DOM element that can be controlled by an attacker. \n\n Not all XSS bugs require the attacker to control the content returned from the server, but can instead abuse poor JavaScript coding practices. In comparison to other cross site scripting vulnerabilities, where an unsanitized parameter is passed by the server, returned to the user and executed in the context of the user’s browser, a DOM-based XSS vulnerability controls the flow of the code by using elements of the Document Object Model (DOM) along with code crafted by the attacker to change the flow. \n Due to their nature, DOM-based XSS vulnerabilities can be executed in many instances without the server being able to determine what is actually being executed. \n\n An attacker may append #<script>alert(‘xss’)</script> to the affected page URL which would, when executed, display the alert box. In this instance, the appended code would not be sent to the server as everything after the # character is not treated as part of the query by the browser but as a fragment. \n\n Testing for DOM-Based XSS vulnerabilities:\n Blackbox testing for DOM-Based XSS is not usually performed since access to the source code is always available as it needs to be sent to the client to be executed. \n Many websites rely on large libraries of functions, which often stretch into the hundreds of thousands of lines of code and have not been developed in-house. In these cases, top-down testing often becomes the only really viable option. \n The same can also be said for top-down testing if the inputs or lack thereof is not identified to begin with. User input comes in two main forms: \n • Input written to the page by the server in a way that does not allow direct XSS \n • Input obtained from client-side JavaScript objects \n\n Automated testing has only very limited success at identifying and validating DOM-based XSS as it usually identifies XSS by sending a specific payload and attempts to observe it in the server response. \n Manual testing should therefore be undertaken and can be done by examining areas in the code where parameters are referred to that may be useful to an attacker.",
|
||||
"002": "A JavaScript Injection vulnerability is a subtype of Cross Site Scripting (XSS) that involves the ability to inject arbitrary JavaScript code that is executed by the application inside the victim’s browser. \n This vulnerability can have many consequences, like disclosure of a user’s session cookies that could be used to impersonate the victim, or, more generally, it can allow the attacker to modify the page content seen by the victims or the application behavior. \n\n Such vulnerability occurs when the application lacks of a proper user supplied input and output validation. JavaScript is used to dynamically populate web pages, this injection occur during this content processing phase and consequently affect the victim. \n When trying to exploit this kind of issues, consider that some characters are treated differently by different browsers.",
|
||||
"003": "HTML injection is a type of injection issue that occurs when a\nuser is able to control an input point and is able to inject arbitrary HTML code into a vulnerable web page. \nThis vulnerability can have many consequences, like disclosure\nof a user’s session cookies that could be used to impersonate the\nvictim, or, more generally, it can allow the attacker to modify the\npage content seen by the victims. \n\n This vulnerability occurs when the user input is not correctly sanitized and the output is not encoded. An injection allows the attacker to send a malicious HTML page to a victim. The targeted browser will not be able to distinguish (trust) the legit from the malicious parts and consequently will parse and execute all as legit in the victim context. \n\n There is a wide range of methods and attributes that could be used to render HTML content. If these methods are provided with an untrusted input, then there is an high risk of XSS. \n Malicious HTML code could be injected for example via innerHTML, that is used to render user inserted HTML code. An improper usage of this property, that means lack of sanitization from untrusted input and missing output encoding. \n If strings are not correctly sanitized the problem could lead to XSS based HTML injection.\n Another method could be document.write() \n\n When trying to exploit this kind of issues, consider that some characters are treated differently by different browsers.",
|
||||
"004": "Client Side URL Redirection, also known as Open Redirection, is an input validation flaw that exists when an application accepts an user controlled input which specifies a link that leads to an external URL that could be malicious. \nThis kind of vulnerability could be used to accomplish a phishing attack or redirect a victim to an infection page. \n\nThis vulnerability occurs when an application accepts untrusted input that contains an URL value without sanitizing it. This URL value could cause the web application to redirect the user to another page as, for example, a malicious page controlled by the attacker. \n\n By modifying untrusted URL input to a malicious site, an attacker may successfully launch a phishing scam and steal user credentials.\n Moreover open redirections could also be used to maliciously craft an URL that would bypass the application’s access control checks and then forward the attacker to privileged functions that they would normally not be able to access. \n\n Testing for Client Side URL Redirect vulnerabilities: \nWhen testers have to manually check for this type of vulnerability they have to identify if there are client side redirections implemented in the client side code. \n These redirections could be implemented, for example in JavaScript, using the “window.location” object that can be used to take the browser to another page by simply assigning a string to it. If the script does not perform any validation of the variable “redir”, then this unvalidated input is passed to the windows.location object originating a URL redirection vulnerability.",
|
||||
"005": "A CSS Injection vulnerability involves the ability to inject arbitrary CSS code in the context of a trusted web site, and this will be rendered inside the victim’s browser. \nThe impact of such a vulnerability may vary on the basis of the supplied CSS payload: it could lead to Cross-Site Scripting in particular circumstances, to data exfiltration in the sense of extracting sensitive data or to UI modifications. \n\n Such a vulnerability occurs when the application allows to supply user-generated CSS or it is possible to somehow interfere with the legit stylesheets. \n Injecting code in the CSS context gives the attacker the possibility to execute JavaScript in certain conditions as well as extracting sensitive values through CSS selectors and functions able to generate HTTP requests. \n\n Specifically the attacker could target the victim by asking her to visit the following URLs: \n • www.victim.com/#red;-o-link:’javascript:alert(1)’;-o-linksource:current; (Opera [8,12]) \n • www.victim.com/#red;-:expression(alert(URL=1)); (IE 7/8) \n\n Much more interesting attack scenarios involve the possibility to extract data through the adoption of pure CSS rules. \nSuch attacks can be conducted through CSS selectors and leading for instance to grab anti-CSRF tokens. \n\n Testing for CSS Injection vulnerabilities: \n Manual testing needs to be conducted and the JavaScript code analyzed in order to understand whether the attackers can inject its own content in CSS context. In particular we should be interested in how the website returns CSS rules on the basis of the inputs.",
|
||||
"006": "A ClientSide Resource Manipulation vulnerability is an input validation flaw that occurs when an application accepts an user controlled input which specifies the path of a resource (i.e. source of an iframe, js, applet). \nSpecifically, such a vulnerability consists in the ability to control the URLs which link to some resources present in a web page. \n The impact may vary on the basis of the type of\the element whose URL is controlled by the attacker, and it is usually adopted to conduct Cross-Site Scripting attacks. \n\n Such a vulnerability occurs when the application employs user\ncontrolled URLs for referencing external/internal resources. \n In these circumstances it is possible to interfere with the expected application’s behavior in the sense of making it load and render malicious objects. \n\n Testing for Client Side Resource Manipulation vulnerabilities:\nTo manually check for this type of vulnerability we have to identify whether the application employs inputs without correctly validating them; these are under the control of the user which could be able to specify the url of some resources. \n Since there are many resources that could be included into the application, client side scripts which handle the associated URLs should be investigated for potential issues. \n\n The following shows the possible injection points (sink) that should be checked: \n • Resource: Frame \n • Tag/Method: iframe \n • Sink: src \n\n • Resource: Link \n • Tag/Method: a \n • Sink: href\n\n • Resource: AJAX Request \n • Tag/Method: xhr.open(method, [url], true); \n • Sink: URL href\n\n • Resource: CSS \n • Tag/Method: link \n\n • Resource: Image \n • Tag/Method: img \n\n • Resource: Object \n • Tag/Method: object \n • Sink: src\n\n • Resource: Script \n • Tag/Method: script \n • Sink: data src",
|
||||
"007": "Cross Origin Resource Sharing or CORS is a mechanism that enables a web browser to perform “cross-domain” requests using the XMLHttpRequest L2 API in a controlled manner. \n In the past, the XMLHttpRequest L1 API only allowed requests to be sent within the same origin as it was restricted by the same origin policy. \n\n Cross-Origin requests have an Origin header, that identifies the domain initiating the request and is always sent to the server. CORS defines the protocol to use between a web browser and a server to determine whether a cross-origin request is allowed. \n In order to accomplish this goal, there are a few HTTP headers involved in this process, that are supported by all major browsers including: \n • Origin \n • Access-Control-Request-Method \n • Access-Control-Request-Headers \n • Access-Control-Allow-Origin \n • Access-Control-Allow-Credentials \n • Access-Control-Allow-Methods \n • Access-Control-Allow-Headers \n\n The CORS specification mandates that for non simple requests, such as requests other than GET or POST or requests that uses credentials, a pre-flight OPTIONS request must be sent in advance to check if the type of request will have a bad impact on the data.\n The pre-flight request checks the methods, headers allowed by the server, and if credentials are permitted, based on the result of the OPTIONS request, the browser decides whether the request is allowed or not. \n\n Check the HTTP headers in order to understand how CORS is used, in particular we should be very interested in the Origin header to learn which domains are allowed. \n Also, manual inspection of the JavaScript is needed to determine whether the code is vulnerable to code injection due to improper handling of user supplied input.",
|
||||
"008": "ActionScript is the language, based on ECMAScript, used by Flash applications when dealing with interactive needs. \n There are three\nversions of the ActionScript language. ActionScript 1.0 and ActionScript 2.0 are very similar with ActionScript 2.0 being an extension of ActionScript 1.0. ActionScript 3.0, introduced with Flash Player 9, is a rewrite of the language to support object orientated design. \n\n ActionScript, like every other language, has some implementation patterns which could lead to security issues.\n In particular, since Flash applications are often embedded in browsers, vulnerabilities like DOM based Cross-Site Scripting (XSS) could be present in flawed Flash applications.\n\n Decompilation \n Since SWF files are interpreted by a virtual machine embedded in the player itself, they can be potentially decompiled and analysed. The most known and free ActionScript 2.0 decompiler is flare. \n Decompilation helps testers because it allows for source code assisted, or white-box, testing of the Flash applications. HP’s free SWFScan tool can decompile both ActionScript 2.0 and ActionScript 3.0.\n\n Attacks and Flash Player Version Since May 2007, three new versions of Flash player were released by Adobe. Every new version restricts some of the attacks. \n\n Player Version: v9.0 r47/48 \n • asfunction: Yes \n • Externalinterface: Yes \n • GetURL: Yes \n • HTML Injection: Yes\n\n Player Version: v9.0 r115 \n • asfunction: No \n • Externalinterface: Yes \n • GetURL: Yes \n • HTML Injection: Yes\n\n Player Version: v9.0 r124 \n • asfunction: No \n • Externalinterface: Yes \n • GetURL: Yes \n • HTML Injection: Partially",
|
||||
"009": "“Clickjacking” (which is a subset of the “UI redressing”) is a malicious technique that consists of deceiving a web user into interacting with something different to what the user believes they are interacting with. \n This type of attack, that can be used alone or in combination with other attacks, could potentially send unauthorized commands or reveal confidential information while the victim is interacting on seemingly harmless web pages. \n\n A Clickjacking attack uses seemingly innocuous features of HTML and Javascript to force the victim to perform undesired actions, such as clicking on a button that appears to perform another operation. \n\n To carry out this type of technique the attacker has to create a seemingly harmless web page that loads the target application through the use of an iframe. \n Once this is done, the attacker could induce the victim to interact with his fictitious web page.\nOnce the victim is surfing on the fictitious web page, he thinks that he is interacting with the visible user interface, but effectively he is performing actions on the hidden page.\n\nThis type of attack is often designed to allow an attacker site to induce user’s actions on the target site even if anti-CSRF tokens are being used. . So it’s important, like for the CSRF attack, to individuate web pages of the target site that it take input from the user.\n\nWe have to discover if the website that we are testing has no protections against clickjacking attacks or, if the developers have implemented some forms of protection, if these techniques are liable to bypass. \nMethods to protect a web page from clickjacking can be divided in two macro-categories: \n • Client side protection: Frame Busting \n • Server side protection: X-Frame-Options \n\n Some frame busting techniques try to break frame by assigning a value to the “parent.location” attribute in the “counter-action” statement. Such actions are, for example: \n • self.parent.location = document.location \n • parent.location.href = self.location \n • parent.location = self.location",
|
||||
"010": "Traditionally the HTTP protocol only allows one request/response per TCP connection. Asynchronous JavaScript and XML (AJAX) allows clients to send and receive data asynchronously to the server, however, AJAX requires the client to initiate the requests and wait for the server responses (half-duplex). \n\n HTML5 WebSockets allow the client/server to create a ‘full-duplex’ (two-way) communication channels, allowing the client and server to truly communicate asynchronously. WebSockets conduct their initial ‘upgrade’ handshake over HTTP and from then on all communication is carried out over TCP channels by use of frames. \n\n 1: Identify that the application is using WebSockets \n • Inspect the client-side source code for the ws:// or wss:// URI scheme\n • Use Browser Developer Tools to view the Network WebSocket communication \n • Use OWASP Zed Attack Proxy (ZAP)’s WebSocket tab \n\n 2: Origin \n • Using a WebSocket client attempt to connect to the remote WebSocket server \n • If a connection is established the server may not be checking the origin header of the WebSocket handshake \n\n 3: Confidentiality and Integrity \n • Check that the WebSocket connection is using SSL to transport sensitive information (wss://) \n • Check the SSL Implementation for security issues s (Valid Certificate, BEAST, CRIME, RC4, etc). \n\n 4: Authentication \n • WebSockets do not handle authentication, normal black box authentication tests should be carried out \n\n 5: Authorization \n • WebSockets do not handle authorization, normal black-box authorization tests should be carried out \n\n 6: Input Sanitization \n • Use OWASP Zed Attack Proxy (ZAP)’s WebSocket tab to replay and fuzz WebSocket request and responses",
|
||||
"011": "Web Messaging (also known as Cross Document Messaging) allows applications running on different domains to communicate in a secure manner. \n This restriction within the browser is in place to restrict a malicious website to read confidential data from other iframes, tabs, etc, however there are some legitimate cases where two trusted websites need to exchange data between each other. To meet this need Cross Document Messaging was introduced within he WHATWG HTML5 draft specification and implemented in all major browsers. \n It enables secure communication between multiple origins across iframes, tabs and windows. \n\n The Messaging API introduced the postMessage() method, with which plain-text messages can be sent cross-origin. It consists of two parameters, message and domain. \n\n There are some security concerns when using ‘*’ as the domain that we discuss below. Then, in order to receive messages the receiving website needs to add a new event handler, and has the following attributes: \n • data: The content of the incoming message \n • origin: The origin of the sender document \n • source: source window \n\nManual testing needs to be conducted and the JavaScript code analyzed looking for how Web Messaging is implemented. \nIn particular we should be interested in how the website is restricting messages from untrusted domain and how the data is handled even for trusted domains.",
|
||||
"012": "Local Storage also known as Web Storage or Offline Storage is a mechanism to store data as key/value pairs tied to a domain and enforced by the same origin policy (SOP). \n There are two objects, localStorage that is persistent and is intended to survive browser/system reboots and sessionStorage that is temporary and will only exists until the window or tab is closed. \n On average browsers allow to store in this storage around 5MB per domain, that compared to the 4KB of cookies is a big difference, but the key difference from the security perspective is that the data stored in these two objects is kept in the client and never sent to the server. \n\n First of all, we need to check whether the Local Storage is used. This can be checked when using the Browser Tool and then go under Resources you will see ‘Local Storage’ and ‘Web Storage’. \n\n Next manual testing needs to be conducted in order to determine whether the website is storing sensitive data in the storage that represents a risk and will increase dramatically the impact of a information leak. \n Also check the code handling the Storage to determine if it is vulnerable to injection attacks, common issue when the code does not escape the input or output.",
|
||||
"013": "Cross Site Script Inclusion (XSSI) vulnerability allows sensitive data leakage across-origin or cross-domain boundaries. Sensitive data could include authentication-related data (login states, cookies, auth tokens, session IDs, etc.) or user’s personal or sensitive personal data (email addresses, phone numbers, credit card details, social security numbers, etc.). XSSI is a client-side attack similar to Cross Site Request Forgery (CSRF) but has a different purpose. \n\nWhere CSRF uses the authenticated user context to execute certain state-changing actions inside a victim’s page (e.g. transfer money to the attacker’s account, modify privileges, reset password, etc.), XSSI instead uses JavaScript on the client-side to leak sensitive data from authenticated sessions.\n\nTest Objectives \n• Locate sensitive data across the system. \n• Assess the leakage of sensitive data through various techniques.\n\nHow to Test\n• Collect Data Using Authenticated and Unauthenticated User Sessions\n• Determine Whether the Sensitive Data Can Be Leaked Using JavaScript\n• Check for Sensitive Data Leakage via Global Variables\n• Check for Sensitive Data Leakage via Global Function Parameters\n• Check for Sensitive Data Leakage via JavaScript Runtime Errors\n• Check for Sensitive Data Leakage via Prototype Chaining Using “this”"
|
||||
},
|
||||
"api": {
|
||||
"001": "GraphQL has become very popular in modern APIs. It provides simplicity and nested objects, which facilitate faster development. While every technology has advantages, it can also expose the application to new attack surfaces. The purpose of this scenario is to provide some common misconfigurations and attack vectors on applications that utilize GraphQL.\n\nTest Objectives:\n• Assess that a secure and production-ready configuration is deployed.\n• Assess that a secure and production-ready configuration is deployed.\n• Ensure that proper access controls are applied.\n\nTesting GraphQL nodes is not very different than testing other API technologies.\nIntrospection queries are the method by which GraphQL lets you ask what queries are supported, which data types are available, and many more details you will need when approaching a test of a GraphQL deployment.\nA tool such as GraphQL Voyager can be used to get a better understanding of the GraphQL endpoint. This tool creates an Entity Relationship Diagram (ERD) representation of the GraphQL schema, allowing you to get a better look into the moving parts of the system you’re testing.\n\nIntrospection is the first place to look for authorization problems. As noted, access to introspection should be restricted as it allows for data extraction and data gathering. Once a tester has access to the schema and knowledge of the sensitive information there is to extract, they should then send queries that will not be blocked due to insufficient privileges. GraphQL does not enforce permissions by default, and so it is up to the application to perform authorization enforcement.\nTesting the authorization implementation varies from deployment to deployment since each schema will have different sensitive information, and hence, different targets to focus on.\n\nGraphQL is the implementation of the API layer of an application, and as such, it usually forwards the requests to a back end API or the database directly. This allows you to utilize any underlying vulnerability such as SQL injection, command injection, cross-site scripting, etc. Using GraphQL just changes the entry point of the malicious payload.\n\nGraphQL can encounter unexpected errors during runtime. When such an error occurs, the server may send an error response that may reveal internal error details or application configurations or data. This allows a malicious user to acquire more information about the application. As part of testing, error messages should be checked by sending unexpected data, a process known as fuzzing. The responses should be searched for potentially sensitive information that may be revealed using this technique."
|
||||
},
|
||||
"no_info": "No information for given reference number found."
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue