Skip to content
Snippets Groups Projects
Commit e53b7579 authored by tom.ryser's avatar tom.ryser :carousel_horse:
Browse files

End of project

parents
No related branches found
No related tags found
No related merge requests found
20230126115153.png

43 KiB

20230126115257.png

34.1 KiB

20230126115500.png

63.5 KiB

20230126115520.png

50.9 KiB

20230126115603.png

50.1 KiB

20230130041332.png

47.1 KiB

20230130042045.png

14.3 KiB

20230130043622.png

41.3 KiB

20230130045344.png

28.1 KiB

20230130054711.png

72.6 KiB

20230130060201.png

90.3 KiB

20230130060242.png

82.6 KiB

20230130062212.png

83.6 KiB

20230130071204.png

68.6 KiB

# syntax=docker/dockerfile:1
FROM golang:1.18-alpine
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY *.go ./
RUN go get .
RUN go build -o /appsec
EXPOSE 8080
CMD [ "/appsec" ]
\ No newline at end of file
This diff is collapsed.
Raport.jpeg

2.31 MiB

Raport.md 0 → 100644
# AppSec Rapport - Tom Ryser
- [AppSec Rapport - Tom Ryser](#appsec-rapport---tom-ryser)
- [API Restful en Golang](#api-restful-en-golang)
- [Installation](#installation)
- [Création de l'app Go](#création-de-lapp-go)
- ["Containerize" le code go dans Docker](#containerize-le-code-go-dans-docker)
- [Sécurisation avec TLS](#sécurisation-avec-tls)
- [Prérequis](#prérequis)
- [Génération des clés TLS](#génération-des-clés-tls)
- [Configuration Nginx](#configuration-nginx)
- [Docker-compose](#docker-compose)
- [Athentification et Authorisation](#athentification-et-authorisation)
- [Implémentez les Athentifications](#implémentez-les-athentifications)
- [Authentification simple](#authentification-simple)
- [Resultat](#resultat)
- [Authentification OIDC](#authentification-oidc)
- [Validation de token](#validation-de-token)
- [Test avec Postman](#test-avec-postman)
- [Gestion des données sensibles](#gestion-des-données-sensibles)
- [Problèmes encontré](#problèmes-encontré)
## API Restful en Golang
### Installation
- Installer Go
`$ sudo snap go`
- Installer Docker
`$ sudo apt install docker`
### Création de l'app Go
Dans le dossier appSec j'ai créé un le fichier main.go avec les commandes suivantes.
```
$ go mod init appSec/myApp
$ touch main.go
```
Le fichier `main.go` contient les imports du projet, les structures (student & teacher) et leurs déclarations, ainsi que les routes HTTP.
```go
package main
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
jwtverifier "github.com/okta/okta-jwt-verifier-golang"
)
// Start of struct
type student struct {
ID string `json:"id"`
Lastname string `json:"lastName"`
Name string `json:"name"`
Filiere string `json:"filiere"`
}
type teacher struct {
ID string `json:"UUID"`
Name string `json:"Name"`
Lastname string `json:"Last name"`
Class string `json:"ClassName"`
}
// End of struct
// Start of data
var students = []student{
{ID: "1", Lastname: "Toto", Name: "Tata", Filiere: "Architecture"},
{ID: "2", Lastname: "Tom", Name: "Ryser", Filiere: "Informatique"},
{ID: "3", Lastname: "Doe", Name: "maxim", Filiere: "Architecture"},
}
var teachers = []teacher{
{ID: "1", Lastname: "Doe", Name: "Joe", Class: "A"},
{ID: "2", Lastname: "Bob", Name: "Martin", Class: "B"},
}
// End of data
// Start of student route functions
func getStudents(c *gin.Context) {
c.IndentedJSON(http.StatusOK, students)
}
func getStudentByID(c *gin.Context) {
id := c.Param("id")
for _, a := range students {
if a.ID == id {
c.IndentedJSON(http.StatusOK, a)
return
}
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "student not found"})
}
func postStudent(c *gin.Context) {
var newStudent student
if err := c.BindJSON(&newStudent); err != nil {
return
}
students = append(students, newStudent)
c.IndentedJSON(http.StatusCreated, newStudent)
}
func deleteStudentById(c *gin.Context) {
id := c.Param("id")
index := 0
for _, student := range students {
if student.ID == id {
students = append(students[:index], students[index+1:]...)
c.IndentedJSON(http.StatusOK, students)
return
}
index += 1
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "student not found"})
}
// End of student route functions
// Start of teacher route functions
func getTeachers(c *gin.Context) {
c.IndentedJSON(http.StatusOK, teachers)
}
func getTeacherById(c *gin.Context) {
id := c.Param("id")
for _, teacher := range teachers {
if teacher.ID == id {
c.IndentedJSON(http.StatusOK, teacher)
return
}
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "teacher not found"})
}
func postTeacher(c *gin.Context) {
var newTeacher teacher
if err := c.BindJSON(&newTeacher); err != nil {
return
}
teachers = append(teachers, newTeacher)
c.IndentedJSON(http.StatusCreated, newTeacher)
}
func deleteTeacherById(c *gin.Context) {
id := c.Param("id")
index := 0
for _, teacher := range teachers {
if teacher.ID == id {
teachers = append(teachers[:index], teachers[index+1:]...)
c.IndentedJSON(http.StatusOK, teachers)
return
}
index += 1
}
c.IndentedJSON(http.StatusNotFound, gin.H{"message": "teacher not found"})
}
// End of teacher route functions
func main() {
r := gin.Default()
r.GET("/students", getStudents)
r.GET("/students/:id", getStudentByID)
r.GET("/teachers", getTeachers)
r.GET("/teachers/:id", getTeacherById)
r.Run("localhost:8080")
}
```
Comment exécuter le code go et vérifier le résultat.
`$ go get .`
`$ go run .`
`$ curl http://localhost:8080/students`
![](20230130041332.png)
### "Containerize" le code go dans Docker
J'ai créé un fichier Dockerfile avec les instructions pour construire la nouvelle image.
```dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.18-alpine
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY *.go ./
RUN go build -o /appsec
EXPOSE 8080
CMD [ "/appsec" ]
```
Puis j'ai utilisé la commande suivante pour construire l'image que j'ai configurée préalablement.
```
docker build --tag docker-appsec_go .
```
Lors du démarrage du container je dois utiliser la commande suivante pour qu'il ait accès au port 8080
`$ docker run -p 8080:8080 docker-appsec_go`
## Sécurisation avec TLS
### Prérequis
```
nginx, docker-compose
Fichier nginx.conf donné par l'enseignant.
$ docker pull nginx
```
### Génération des clés TLS
J'ai utilisé la commande suivante pour générer les clés TLS, J'ai donné les réponses suivantes même si elles ne sont pas importantes.
`$ openssl req -x509 -newkey rsa:4096 -keyout certs/key.pem -out certs/cert.pem -days 365 -nodes`
```
result:
Country name : CH
State : Geneva
Locality : Lancy
Organization : HEPIA
Organizational unit : IT
Common name : Tom
Email : tom.ryser@etu.hesge.ch
```
### Configuration Nginx
Voici le fichier de configuration de Nginx.
```Nginx
user www www; ## Default: nobody
worker_processes 5; ## Default: 1
error_log logs/error.log;
pid logs/nginx.pid;
worker_rlimit_nofile 8192;
events { }
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name localhost;
return 301 https://localhost$request_uri;
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /certs/cert.pem;
ssl_certificate_key /certs/key.pem;
access_log /var/log/nginx/data-access.log combined;
location / {
proxy_pass http://appSec:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
#proxy_redirect http://shiny:3838/ $scheme://$http_host/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 20d;
proxy_buffering off;
}
}
}
```
### Docker-compose
J'ai créé le fichier `docker-compose.yml` avec le contenu suivant.
```yml
version: '3'
services:
nginx:
image: nginx:latest
container_name: nginx
volumes:
- .:/nginx.conf
- ./certs:/certs
ports:
- 80:80
- 443:443
appsec:
image: docker-appsec_go:latest
container_name: appsec
expose:
- "8080"
```
Puis j'ai utilisé la commande `$ docker compose up -d` pour construire le docker.
Maintenant quand je vais sur "localhost:8080/students" J'ai une erreur "connection refused". L'erreur semble provenir de docker, mais je ne sais pas pourquoi.
![](20230130042045.png)
## Athentification et Authorisation
### Implémentez les Athentifications
#### Authentification simple
Pour l'authentification simple, j'ai rajouter 2 groupes:
- AuthorizedGet
- user1 (admin)
- user2 (visiteur)
- authorizedAll
- user1 (admin)
```go
r := gin.Default()
authorizedGet := r.Group("/", gin.BasicAuth(gin.Accounts{
"foo": "bar",
"aristote": "Eucl1de",
}))
authorizedAll := r.Group("/", gin.BasicAuth(gin.Accounts{
"aristote": "Eucl1de",
}))
```
##### Resultat
![](20230130043622.png)
#### Authentification OIDC
J'ai commencé par créer 3 utilisateurs dans okta.
![](20230126115257.png)
Puis j'ai créer une intégration d'application.
![](20230126115500.png)
![](20230126115520.png)
![](20230126115603.png)
#### Validation de token
Après avoir configuré Okta j'ai dû installer le paquet Okta pour l'application go, et l'ajouter dans les imports.
```
$ go get -u github.com/okta/okta-jwt-verifier-golang
```
```go
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/okta/okta-jwt-verifier-golang"
"strings"
)
```
Ajout de la fonction pour valider le token
```go
var toValidate = map[string]string{
"aud": "api://default",
"cid": "<client-id>",
}
```
Il faut remplacer `<client-id>` par la valeur correspondant à l'audience.
![](20230130045344.png)
Pour finir il faut valider le token, et pour ce faire J'ai modifié mon import.
```go
import (
"net/http"
"os"
"strings"
"github.com/gin-gonic/gin"
jwtverifier "github.com/okta/okta-jwt-verifier-golang"
)
```
Puis j'ai rajouter une fonction `verify()`.
```go
func verify(c *gin.Context) bool {
status := true
token := c.Request.Header.Get("Authorization")
if strings.HasPrefix(token, "Bearer ") {
token = strings.TrimPrefix(token, "Bearer ")
verifierSetup := jwtverifier.JwtVerifier{
Issuer: "https://" + os.Getenv("OKTA_DOMAIN") + "/oauth2/default",
ClaimsToValidate: toValidate,
}
verifier := verifierSetup.New()
_, err := verifier.VerifyAccessToken(token)
if err != nil {
c.String(http.StatusForbidden, err.Error())
print(err.Error())
status = false
}
} else {
c.String(http.StatusUnauthorized, "Unauthorized")
status = false
}
return status
}
```
source: https://developer.okta.com/blog/2021/02/17/building-and-securing-a-go-and-gin-web-application#how-to-validate-an-access-token-in-go
#### Test avec Postman
- Installation
- Pour installer postman j'ai utilisé la commande
```
$ sudo snap install postman
```
- Configuration
- ![](20230130060242.png)
-
- Obtention du token
- Au bas de la page se trouve un bouton "Get new access token" qui ouvre un navigateur, après avoir entré les informations de login d'un utilisateur, l'on obtient un token d'accès.
- ![](20230130060201.png)
- Ajout des droits dans le `main.go`
```go
//OKTA auth
authorization["bob.idiot@gmail.com"] = append(authorization["bob.idiot@gmail.com"], "GET")
authorization["jean.intellignet@gmail.com"] = append(authorization["jean.intellignet@gmail.com"], "GET", "POST", "DELETE", "DELETE")
authorizedOkta := r.Group("/")
authorizedOkta.GET("/students", getStudents)
authorizedOkta.GET("/student/:id", getStudentByID)
authorizedOkta.POST("/students", postStudent)
authorizedOkta.DELETE("/student/:id", deleteStudentById)
authorizedOkta.GET("/teachers", getTeachers)
authorizedOkta.GET("/teacher/:id", getTeacherById)
authorizedOkta.POST("/teachers", postTeacher)
authorizedOkta.DELETE("/teacher/:id", deleteTeacherById)
```
![](20230130071204.png)
## Gestion des données sensibles
Pour cette partie j'ai modifier mon code pour cacher les identifiants écrit en claire.
Pour ce faire j'ai créer un fichier `.env` dont on appel la correspondence comme ceci `os.Getenv("FOO)`
```.env
FOO="foo:bar"
ARI="aristote:Euclide"
```
Je n'ai pas eu le temps d'aller plus loin.
## Problèmes encontré
Lors de ce projet j'ai été confronté à plusieurs problèmes.
- Docker
- Lorsque je voulais arrêter un docker, j'obtenais une erreur qui me disait que je n'avais pas les droits nécessaires.
- Après avoir complètement désinstallé docker je l'ai réinstaller en version dektop. Ce qui semble avoir fixé mon problème.
- J'ai par la suite eu de nouveaux problèmes avec docker et j'ai donc continué le projet sans.
- Postman
- Après avoir installé l'application, au lancement j'ai obtenu une erreur qui faisait planter l'application.
- J'ai dû réinstaller l'application 2 fois et suis suivi des tutos différents pour chaque installation.
\ No newline at end of file
File added
Raport.png

1.74 MiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment