Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ DB_NAME=study-project
STORE_DB_NAME=store-db
STORE_DB_PSWD=store-pswd
STORE_DB_USER=store-user
STORE_SEC_KEY=store-secret-key

BANK_DB_NAME=bank-db
BANK_DB_PSWD=bank-store
BANK_DB_USER=bank-user
BANK_SEC_KEY=bank-secret-key

DB_PORT=51488
```
Expand All @@ -66,25 +68,25 @@ DB_PORT=51488
### How to get user balance ( example )

```
curl --insecure -X GET -H 'Content-Type: application/json' -u "seregga:seregga" "https://127.0.0.1:5001/api/balance"
curl --insecure -X GET -H 'Content-Type: application/json' -u "seregga:seregga" "https://127.0.0.1/api/bank/api/balance"
```

### How to add account in our great bank ( example )

```
curl --insecure -X POST -H 'Content-Type: application/json' -d '{"uuid" : "test", "password" : "test"}' "https://127.0.0.1:5001/api/add-account"
curl --insecure -X POST -H 'Content-Type: application/json' -d '{"uuid" : "test", "password" : "test"}' "https://127.0.0.1/api/bank/api/add-account"
```

### How to delete bank account ( example )

```
curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" "https://127.0.0.1:5001/api/delete-account"
curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" "https://127.0.0.1/api/bank/api/delete-account"
```

### How to transfer money from one account to another ( example )

```
curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" -d '{"uuid_to" : "seregga", "amount" : 500 }' "https://127.0.0.1:5001/api/transfer"
curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" -d '{"uuid_to" : "seregga", "amount" : 500 }' "https://127.0.0.1/api/bank/api/transfer"
```

### Return codes for bank api service
Expand Down Expand Up @@ -112,15 +114,11 @@ curl --insecure -X POST -H 'Content-Type: application/json' -u "test:test" -d '{
# create test data (optional)
python tools/deGenerator.py

# store.crt and store.key files for store service
cd store-service/
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout store.key -out store.crt
cd ..

# bank.crt and bank.key files for bank service
cd bank-service/
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout bank.key -out bank.crt
cd ..
# create cerificates for reverse-proxy
cd nginx/certs/
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout gamehub.local.key -out gamehub.local.crt
openssl dhparam -out dhparam.pem 2048
cd ../..

# run containers in daemon mode
docker compose up --build -d
Expand Down
3 changes: 1 addition & 2 deletions bank-service/bank/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@

# run flask application
if __name__ == '__main__':
ssl_context = ('bank.crt', 'bank.key')
app.run('0.0.0.0', port=5001, debug=True, ssl_context=ssl_context)
app.run('0.0.0.0', port=5001, debug=True)
30 changes: 17 additions & 13 deletions bank-service/bank/database/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def add_account(uuid:str, password:str):
phash = bcrypt.hashpw(
password.encode('utf-8'),
bcrypt.gensalt(rounds = 12)
).hexdigest()
).decode('utf-8')
conn = get_db()
try:
cursor = conn.cursor()
Expand Down Expand Up @@ -99,28 +99,32 @@ def transfer(id_from:int, uuid_to:str, amount:int):
id_to = cursor.fetchone()
if not id_to:
raise ValueError(f'No recver uuid={uuid_to} in database')
id_to = id_to['id']
id_to = id_to['id']

cursor.execute(
'SELECT balance FROM bank.accounts WHERE id = %s;',
'SELECT id, uuid, balance FROM bank.accounts WHERE id = %s;',
(id_from,)
)
sender_balance = cursor.fetchone()
if not sender_balance or sender_balance['balance'] < amount:

from_data = cursor.fetchone()
if not from_data:
raise ValueError(f'No sender with id={id_from} in database')
uuid_from = from_data['uuid']

if id_from == id_to:
raise ValueError('Why you need to send money for yourself???')

if from_data['balance'] < amount:
raise ValueError('Not enough money :(')

cursor.execute(
'UPDATE bank.accounts SET balance = balance - %s WHERE id = %s;',
(amount, id_from,)
)
cursor.execute(
'UPDATE bank.accounts SET balance = balance + %s WHERE id = %s;',
(amount, id_to,)
'INSERT INTO bank.transactions (user_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);',
(id_from, -amount, uuid_from)
)

cursor.execute(
'INSERT INTO bank.transactions (user_id, amount) VALUES (%s, %s), (%s, %s);',
(id_from, -amount, id_to, amount)
'INSERT INTO bank.transactions (user_id, amount, account_uuid_snapshot) VALUES (%s, %s, %s);',
(id_to, amount, uuid_to)
)

conn.commit()
Expand Down
2 changes: 1 addition & 1 deletion bank-service/uwsgi.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ processes = 4
threads = 2
enable-threads = true

http = 0.0.0.0:5000
http = 0.0.0.0:5001

vacuum = true
buffer-size = 32768
Expand Down
23 changes: 22 additions & 1 deletion database/init-scripts/10-bank-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,28 @@ CREATE TABLE IF NOT EXISTS bank.transactions (
id SERIAL PRIMARY KEY,
ts TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
amount INTEGER NOT NULL,
user_id INTEGER NOT NULL REFERENCES bank.accounts (id),
user_id INTEGER REFERENCES bank.accounts (id) ON DELETE SET NULL,
account_uuid_snapshot TEXT NOT NULL,

FOREIGN KEY (user_id) REFERENCES bank.accounts
);

CREATE OR REPLACE VIEW bank.current_balance AS
SELECT
a.id,
a.uuid,
COALESCE(SUM(t.amount), 0) AS balance
FROM bank.accounts AS a
LEFT JOIN bank.transactions AS t ON a.id = t.user_id
GROUP BY a.id, a.uuid;

CREATE OR REPLACE VIEW bank.all_transactions_view AS
SELECT
t.id,
t.ts,
t.amount,
t.user_id,
COALESCE(a.uuid, t.account_uuid_snapshot) AS related_account_uuid,
(a.id IS NULL) AS is_account_deleted
FROM bank.transactions AS t
LEFT JOIN bank.accounts AS a ON t.user_id = a.id;
38 changes: 33 additions & 5 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ services:
DB_NAME: ${DB_NAME}
DB_USER: ${STORE_DB_USER}
DB_PSWD: ${STORE_DB_PSWD}
SECRET_KEY: ${STORE_SEC_KEY}
volumes:
- ./database/store-init-csvs:/tmp/init-csvs/
networks:
Expand All @@ -47,37 +48,64 @@ services:
build: bank-service
depends_on:
- db
ports:
- "5001:5001"
environment:
DB_HOST: db
DB_PORT: ${DB_PORT}
DB_NAME: ${DB_NAME}
DB_USER: ${BANK_DB_USER}
DB_PSWD: ${BANK_DB_PSWD}
ports:
- "5001:5001"
SECRET_KEY: ${BANK_SEC_KEY}
networks:
- gamehub-net

reverse-proxy:
image: nginx:1.25-alpine
image: owasp/modsecurity-crs:nginx-alpine
container_name: gamehub-rp
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d/app.conf:/etc/nginx/conf.d/app.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/snippets:/etc/nginx/snippets:ro
- nginx_logs:/var/log/nginx
environment:
# On - блокировать, DetectionOnly - только обнаруживать, Off - выключить.
MODSEC_RULE_ENGINE: "Off"
# Уровень паранойи от 1 до 4.
PARANOIA_LEVEL: "1"
# Уровень логирования (error, warn, notice, info, debug)
LOG_LEVEL: "warn"
depends_on:
- store-service
- bank-service
networks:
- gamehub-net
restart: always

ips:
image: jasonish/suricata:latest
container_name: gamehub-suricata
cap_add:
- NET_ADMIN
- NET_RAW
- SYS_NICE
command: -i eth0
volumes:
- ./suricata/conf/suricata.yaml:/etc/suricata/suricata.yaml
- ./suricata/suricata_rules:/var/lib/suricata/rules
- suricata_logs:/var/log/suricata
networks:
- gamehub-net

networks:
gamehub-net:

volumes:
postgres_data:
suricata_rules:
suricata_logs:
nginx_logs:

3 changes: 3 additions & 0 deletions nginx/conf.d/app.conf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ server {

server_name gamehub.local www.gamehub.local;

modsecurity on;

ssl_certificate /etc/nginx/certs/gamehub.local.crt;
ssl_certificate_key /etc/nginx/certs/gamehub.local.key;

Expand All @@ -44,6 +46,7 @@ server {

location / {
proxy_pass http://store_service_upstream/;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Expand Down
41 changes: 41 additions & 0 deletions suricata/conf/suricata.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
%YAML 1.1
---

# Include the default configuration file.
#include: /etc/suricata/suricata.yaml-default

# Overrides for this Docker container.
outputs:
- eve-log:
enabled: yes
filetype: regular
filename: eve.json
types:
- alert:
payload: yes
packet: yes
http: yes
- http:
extended: yes
- dns
- tls:
extended: yes
- files:
force-magic: yes
force-md5: yes
- ssh
- flow
- netflow
- stats:
enabled: yes
filename: stats.log
interval: 8

af-packet:
# Just define the default as we don't know what interface we will be
# run on.
- interface: default
threads: auto
use-mmap: yes
cluster-id: 99
cluster-type: cluster_flow
37 changes: 37 additions & 0 deletions suricata/rules/another.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Custom Suricata rules for GameHub

# Web application security rules
alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: SQL Injection attempt detected"; flow:established,to_server; content:"SELECT"; nocase; content:"FROM"; nocase; distance:0; within:100; classtype:web-application-attack; sid:1000001; rev:1;)

alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: XSS attempt detected"; flow:established,to_server; content:"<script"; nocase; classtype:web-application-attack; sid:1000002; rev:1;)

alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Path traversal attempt"; flow:established,to_server; content:"../"; classtype:web-application-attack; sid:1000003; rev:1;)

alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Command injection attempt"; flow:established,to_server; content:"|3B|"; content:"rm"; nocase; distance:0; within:50; classtype:web-application-attack; sid:1000004; rev:1;)

# Banking service specific rules
alert http $EXTERNAL_NET any -> $HOME_NET 5001 (msg:"GameHub Bank: Unauthorized API access attempt"; flow:established,to_server; content:"POST"; http_method; content:"/api/transfer"; http_uri; content:!"Authorization:"; http_header; classtype:policy-violation; sid:1000010; rev:1;)

alert http $EXTERNAL_NET any -> $HOME_NET 5001 (msg:"GameHub Bank: Large transaction attempt"; flow:established,to_server; content:"amount"; http_client_body; content:"|22|1000000"; http_client_body; distance:0; within:20; classtype:policy-violation; sid:1000011; rev:1;)

# Store service specific rules
alert http $EXTERNAL_NET any -> $HOME_NET 5000 (msg:"GameHub Store: Price manipulation attempt"; flow:established,to_server; content:"price"; http_client_body; content:"|22|0"; http_client_body; distance:0; within:20; classtype:policy-violation; sid:1000020; rev:1;)

alert http $EXTERNAL_NET any -> $HOME_NET 5000 (msg:"GameHub Store: Inventory manipulation"; flow:established,to_server; content:"quantity"; http_client_body; content:"|22|-"; http_client_body; distance:0; within:20; classtype:policy-violation; sid:1000021; rev:1;)

# Database protection rules
alert tcp $EXTERNAL_NET any -> $HOME_NET $DB_PORT (msg:"GameHub DB: Direct database access attempt"; flow:established,to_server; classtype:policy-violation; sid:1000030; rev:1;)

# Brute force protection
alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Brute force login attempt"; flow:established,to_server; content:"POST"; http_method; content:"/login"; http_uri; detection_filter:track by_src, count 5, seconds 60; classtype:attempted-recon; sid:1000040; rev:1;)

# DDoS protection
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Potential DDoS attack"; flow:established,to_server; detection_filter:track by_src, count 100, seconds 10; classtype:attempted-dos; sid:1000050; rev:1;)

# Suspicious user agents
alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Suspicious bot activity"; flow:established,to_server; content:"User-Agent|3A 20|"; http_header; content:"bot"; nocase; http_header; classtype:policy-violation; sid:1000060; rev:1;)

# File upload security
alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: Malicious file upload attempt"; flow:established,to_server; content:"Content-Type|3A 20|application/x-executable"; http_header; classtype:trojan-activity; sid:1000070; rev:1;)

alert http $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"GameHub: PHP file upload attempt"; flow:established,to_server; content:"filename|3D 22|"; http_header; content:".php"; nocase; http_header; distance:0; within:100; classtype:web-application-attack; sid:1000071; rev:1;)
1 change: 1 addition & 0 deletions suricata/rules/my.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alert icmp $HOME_NET any -> 8.8.8.8 any (msg:"TEST ping google"; classtype:not-suspicious; sid:1; rev:1;)