Skip to content

Commit ed791ba

Browse files
authored
Migrate to HttpOnly Cookie Auth + CSRF Protection (#59)
* feat: migrate to HttpOnly cookie auth and add CSRF double submit * chore: update local db host port
1 parent f7700fa commit ed791ba

24 files changed

Lines changed: 857 additions & 213 deletions

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ HTTP_ADDR=:8080
44
SHUTDOWN_TIMEOUT=10s
55
AUTO_MIGRATE=true
66
BCRYPT_COST=12
7+
COOKIE_DOMAIN=
78

89
# PostgreSQL
910
DB_HOST=localhost

docker-compose.db.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ version: "3.9"
33
services:
44
postgres:
55
image: postgres:16
6-
container_name: local-postgres
6+
container_name: local-postgres-smctf
77
restart: unless-stopped
88
ports:
9-
- "5432:5432"
9+
- "25432:5432"
1010
environment:
1111
POSTGRES_DB: app_db
1212
POSTGRES_USER: app_user
@@ -18,10 +18,10 @@ services:
1818

1919
redis:
2020
image: redis:7
21-
container_name: local-redis
21+
container_name: local-redis-smctf
2222
restart: unless-stopped
2323
ports:
24-
- "6379:6379"
24+
- "26379:6379"
2525
command: ["redis-server", "--appendonly", "yes"]
2626
volumes:
2727
- redis_data:/data

docs/docs/admin.md

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ nav_order: 6
1010
Headers
1111

1212
```
13-
Authorization: Bearer <access_token>
13+
Cookie: access_token=<jwt>
1414
```
1515

1616
Request
@@ -57,7 +57,7 @@ Response 200
5757
Errors:
5858

5959
- 400 `invalid input`
60-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
60+
- 401 `invalid token` or `missing access_token cookie`
6161
- 403 `forbidden`
6262

6363
Notes:
@@ -73,7 +73,7 @@ Notes:
7373
Headers
7474

7575
```
76-
Authorization: Bearer <access_token>
76+
Cookie: access_token=<jwt>
7777
```
7878

7979
Response 200
@@ -165,7 +165,7 @@ Notes:
165165

166166
Errors:
167167

168-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
168+
- 401 `invalid token` or `missing access_token cookie`
169169
- 403 `forbidden`
170170

171171
---
@@ -177,7 +177,7 @@ Errors:
177177
Headers
178178

179179
```
180-
Authorization: Bearer <access_token>
180+
Cookie: access_token=<jwt>
181181
```
182182

183183
Request
@@ -215,7 +215,7 @@ Response 201
215215
Errors:
216216

217217
- 400 `invalid input`
218-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
218+
- 401 `invalid token` or `missing access_token cookie`
219219
- 403 `forbidden`
220220

221221
Validation notes:
@@ -231,7 +231,7 @@ Validation notes:
231231
Headers
232232

233233
```
234-
Authorization: Bearer <access_token>
234+
Cookie: access_token=<jwt>
235235
```
236236

237237
Response 200
@@ -263,7 +263,7 @@ Response 200
263263

264264
Errors:
265265

266-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
266+
- 401 `invalid token` or `missing access_token cookie`
267267
- 403 `forbidden`
268268

269269
---
@@ -275,7 +275,7 @@ Errors:
275275
Headers
276276

277277
```
278-
Authorization: Bearer <access_token>
278+
Cookie: access_token=<jwt>
279279
```
280280

281281
Request
@@ -301,7 +301,7 @@ Response 201
301301
Errors:
302302

303303
- 400 `invalid input`
304-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
304+
- 401 `invalid token` or `missing access_token cookie`
305305
- 403 `forbidden`
306306

307307
---
@@ -331,7 +331,7 @@ Response 201
331331
Errors:
332332

333333
- 400 `invalid input`
334-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
334+
- 401 `invalid token` or `missing access_token cookie`
335335
- 403 `forbidden`
336336

337337
---
@@ -343,7 +343,7 @@ Errors:
343343
Headers
344344

345345
```
346-
Authorization: Bearer <access_token>
346+
Cookie: access_token=<jwt>
347347
```
348348

349349
Request
@@ -372,7 +372,7 @@ Response 200
372372
Errors:
373373

374374
- 400 `invalid input`
375-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
375+
- 401 `invalid token` or `missing access_token cookie`
376376
- 403 `forbidden`
377377
- 404 `not found`
378378

@@ -385,7 +385,7 @@ Errors:
385385
Headers
386386

387387
```
388-
Authorization: Bearer <access_token>
388+
Cookie: access_token=<jwt>
389389
```
390390

391391
Request
@@ -414,7 +414,7 @@ Response 200
414414
Errors:
415415

416416
- 400 `invalid input`
417-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
417+
- 401 `invalid token` or `missing access_token cookie`
418418
- 403 `forbidden`
419419
- 404 `not found`
420420

@@ -427,7 +427,7 @@ Errors:
427427
Headers
428428

429429
```
430-
Authorization: Bearer <access_token>
430+
Cookie: access_token=<jwt>
431431
```
432432

433433
Response 200
@@ -448,7 +448,7 @@ Response 200
448448
Errors:
449449

450450
- 400 `invalid input`
451-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
451+
- 401 `invalid token` or `missing access_token cookie`
452452
- 403 `forbidden`
453453
- 404 `not found`
454454

@@ -461,7 +461,7 @@ Errors:
461461
Headers
462462

463463
```
464-
Authorization: Bearer <access_token>
464+
Cookie: access_token=<jwt>
465465
```
466466

467467
Request
@@ -522,7 +522,7 @@ Notes:
522522
Errors:
523523

524524
- 400 `invalid input`
525-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
525+
- 401 `invalid token` or `missing access_token cookie`
526526
- 403 `forbidden`
527527

528528
---
@@ -534,7 +534,7 @@ Errors:
534534
Headers
535535

536536
```
537-
Authorization: Bearer <access_token>
537+
Cookie: access_token=<jwt>
538538
```
539539

540540
Request
@@ -544,19 +544,19 @@ To keep existing values, omit the field entirely.
544544

545545
Field behavior:
546546

547-
| Field | Type | Omit | null | Empty/Whitespace String | Other |
548-
| ----------------------- | ------ | ------------- | ------------ | ----------------------- | --------------------------------------------------------- |
549-
| `title` | string | Keep existing | Error | Allowed | Allowed |
550-
| `description` | string | Keep existing | Error | Allowed | Allowed |
551-
| `category` | string | Keep existing | Error | Error | Must be a valid category |
552-
| `points` | int | Keep existing | Error | Error | Must be >= 0 |
553-
| `minimum_points` | int | Keep existing | Error | Error | Must be >= 0 and <= `points` |
554-
| `flag` | string | Keep existing | Error | Error | Updates flag |
555-
| `previous_challenge_id` | int | Keep existing | Clears value | Error | Must be a valid challenge id (not self) |
556-
| `is_active` | bool | Keep existing | Error | Error | Sets value |
557-
| `stack_enabled` | bool | Keep existing | Error | Error | If `false`, clears `stack_target_ports` + `stack_pod_spec` |
547+
| Field | Type | Omit | null | Empty/Whitespace String | Other |
548+
| ----------------------- | ------ | ------------- | ------------ | ----------------------- | -------------------------------------------------------------------------- |
549+
| `title` | string | Keep existing | Error | Allowed | Allowed |
550+
| `description` | string | Keep existing | Error | Allowed | Allowed |
551+
| `category` | string | Keep existing | Error | Error | Must be a valid category |
552+
| `points` | int | Keep existing | Error | Error | Must be >= 0 |
553+
| `minimum_points` | int | Keep existing | Error | Error | Must be >= 0 and <= `points` |
554+
| `flag` | string | Keep existing | Error | Error | Updates flag |
555+
| `previous_challenge_id` | int | Keep existing | Clears value | Error | Must be a valid challenge id (not self) |
556+
| `is_active` | bool | Keep existing | Error | Error | Sets value |
557+
| `stack_enabled` | bool | Keep existing | Error | Error | If `false`, clears `stack_target_ports` + `stack_pod_spec` |
558558
| `stack_target_ports` | array | Keep existing | Error | Error | Requires `stack_enabled` true; container port 1-65535 and protocol TCP/UDP |
559-
| `stack_pod_spec` | string | Keep existing | Error | Error | Requires `stack_enabled` true and non-empty value |
559+
| `stack_pod_spec` | string | Keep existing | Error | Error | Requires `stack_enabled` true and non-empty value |
560560

561561
If `stack_enabled` is true after updates, `stack_target_ports` and `stack_pod_spec` are required (non-empty).
562562
To clear stack fields, set `stack_enabled` to `false` (and omit `stack_target_ports` / `stack_pod_spec`).
@@ -613,7 +613,7 @@ Notes:
613613
Errors:
614614

615615
- 400 `invalid input`
616-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
616+
- 401 `invalid token` or `missing access_token cookie`
617617
- 403 `forbidden`
618618
- 404 `challenge not found`
619619

@@ -630,7 +630,7 @@ Validation notes:
630630
Headers
631631

632632
```
633-
Authorization: Bearer <access_token>
633+
Cookie: access_token=<jwt>
634634
```
635635

636636
Response 200
@@ -666,7 +666,7 @@ Notes:
666666

667667
Errors:
668668

669-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
669+
- 401 `invalid token` or `missing access_token cookie`
670670
- 403 `forbidden`
671671
- 404 `challenge not found`
672672

@@ -679,7 +679,7 @@ Errors:
679679
Headers
680680

681681
```
682-
Authorization: Bearer <access_token>
682+
Cookie: access_token=<jwt>
683683
```
684684

685685
Response 200
@@ -692,7 +692,7 @@ Response 200
692692

693693
Errors:
694694

695-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
695+
- 401 `invalid token` or `missing access_token cookie`
696696
- 403 `forbidden`
697697
- 404 `challenge not found`
698698

@@ -703,7 +703,7 @@ Errors:
703703
Headers
704704

705705
```
706-
Authorization: Bearer <access_token>
706+
Cookie: access_token=<jwt>
707707
```
708708

709709
### List All Stacks
@@ -735,7 +735,7 @@ Response 200
735735

736736
Errors:
737737

738-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
738+
- 401 `invalid token` or `missing access_token cookie`
739739
- 403 `forbidden`
740740
- 503 `stack feature disabled` or `stack provisioner unavailable`
741741

@@ -766,7 +766,7 @@ Response 200
766766

767767
Errors:
768768

769-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
769+
- 401 `invalid token` or `missing access_token cookie`
770770
- 403 `forbidden`
771771
- 404 `stack not found`
772772
- 503 `stack feature disabled` or `stack provisioner unavailable`
@@ -786,7 +786,7 @@ Response 200
786786

787787
Errors:
788788

789-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
789+
- 401 `invalid token` or `missing access_token cookie`
790790
- 403 `forbidden`
791791
- 404 `stack not found`
792792
- 503 `stack feature disabled` or `stack provisioner unavailable`
@@ -800,7 +800,7 @@ Errors:
800800
Headers
801801

802802
```
803-
Authorization: Bearer <access_token>
803+
Cookie: access_token=<jwt>
804804
```
805805

806806
Request
@@ -846,7 +846,7 @@ Notes:
846846
Errors:
847847

848848
- 400 `invalid input`
849-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
849+
- 401 `invalid token` or `missing access_token cookie`
850850
- 403 `forbidden`
851851
- 404 `challenge not found`
852852
- 503 `storage unavailable`
@@ -860,7 +860,7 @@ Errors:
860860
Headers
861861

862862
```
863-
Authorization: Bearer <access_token>
863+
Cookie: access_token=<jwt>
864864
```
865865

866866
Response 200
@@ -882,7 +882,7 @@ Response 200
882882

883883
Errors:
884884

885-
- 401 `invalid token` or `missing authorization` or `invalid authorization`
885+
- 401 `invalid token` or `missing access_token cookie`
886886
- 403 `forbidden`
887887
- 404 `challenge not found` or `challenge file not found`
888888
- 503 `storage unavailable`

0 commit comments

Comments
 (0)