Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d21b959104 | ||
|
|
2b822af907 | ||
|
|
2aa636409a | ||
|
|
819af38886 | ||
|
|
65fe245e9f | ||
|
|
8ebde5ffbc | ||
|
|
eef425d7b7 | ||
|
|
490ec5b151 | ||
|
|
1e38f4b842 | ||
|
|
827d6fecec | ||
|
|
e3a76baec7 | ||
|
|
f41eb6de51 | ||
|
|
90829b054c | ||
|
|
8db6c5af9f | ||
|
|
e8d34d1bc2 | ||
|
|
520420f863 | ||
|
|
656c3ab073 | ||
|
|
162d69cb93 | ||
|
|
c6506dde33 | ||
|
|
11dc42574b |
@@ -1,27 +0,0 @@
|
||||
name: Docker Build and Push
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: docker
|
||||
if: branch == 'main'
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login to Registry
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ secrets.REGISTRY_URL }} -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||
|
||||
- name: Build Docker Image
|
||||
run: |
|
||||
docker build -t ${{ secrets.REGISTRY_URL }}/FlorianWalther/password-generator:latest .
|
||||
|
||||
- name: Push Docker Image
|
||||
run: |
|
||||
docker push ${{ secrets.REGISTRY_URL }}/FlorianWalther/password-generator:latest
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
docker system prune -f
|
||||
|
||||
30
.gitea/workflows/docker-release.yml
Normal file
30
.gitea/workflows/docker-release.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
iname: Docker Release Build
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*' # Reagiert auf Tags die mit 'v' beginnen, z.B. v1.0.2
|
||||
|
||||
jobs:
|
||||
push_to_registry:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login to Gitea
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }} # gitea.scu.si
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
# Hier wird die Git-Referenz automatisch als Docker-Tag genutzt
|
||||
#tags: gitea.scu.si/florianwalther/password-generator:${{ gitea.ref_name }}
|
||||
tags: |
|
||||
gitea.scu.si/florianwalther/password-generator:${{ gitea.ref_name }}
|
||||
gitea.scu.si/florianwalther/password-generator:latest
|
||||
39
README.md
39
README.md
@@ -1,26 +1,29 @@
|
||||
# Web-Password
|
||||
|
||||
# Funktionsweise
|
||||
_a web based password generator_
|
||||
|
||||
* Passwortgenerierung: Die Anwendung generiert ein 32-stelliges Passwort mit Großbuchstaben, Kleinbuchstaben und Ziffern (entspricht dem Befehl `apg -a 1 -m 32 -n 1 -M NCL`).
|
||||
* Zwischenablage: Mit dem Button "In Zwischenablage kopieren" wird das Passwort in die Zwischenablage kopiert.
|
||||
* Docker: Der Container enthält nur die Go-Anwendung und keine zusätzliche Linux-Distribution.
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
# Baue die Go-Anwendung
|
||||
* generates long and random, secure passwords (read about the [security considerations](SECURITY.md))
|
||||
* copy to clipboard
|
||||
* very small docker container, that only contains the application and has minimum attack surface
|
||||
|
||||
## Demo
|
||||
|
||||
There is a demo at [https://passwd.scu.si](https://passwd.scu.si)
|
||||
|
||||
## Usage
|
||||
|
||||
The follwoing example shows how to get up your own instance with `docker compose`.
|
||||
|
||||
```
|
||||
go build -o password-generator ./
|
||||
```
|
||||
|
||||
# Baue das Docker-Image
|
||||
|
||||
```
|
||||
docker build -t password-generator .
|
||||
```
|
||||
|
||||
# Starte den Docker Container
|
||||
|
||||
```
|
||||
docker run -p 8080:8080 password-generator
|
||||
git clone https://gitea.scu.si/FlorianWalther/Web-Password.git
|
||||
cd Web-Password
|
||||
cp misc/docker-compose.yml ./
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
There are some more usage example in [misc/MoreUsage.md](misc/MoreUsage.md)
|
||||
|
||||
110
SECURITY.md
Normal file
110
SECURITY.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Security Considerations
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
This document analyzes the security of passwords generated by the application, which uses the following parameters:
|
||||
- Length: 32 characters
|
||||
- Character set: Uppercase letters (A-Z), lowercase letters (a-z), digits (0-9)
|
||||
- No special characters (equivalent to `apg -a 1 -m 32 -n 1 -M NCL`)
|
||||
|
||||
---
|
||||
|
||||
## 2. Keyspace Analysis
|
||||
### 2.1. Character Set and Length
|
||||
- Character set size: 26 (uppercase) + 26 (lowercase) + 10 (digits) = **62 possible characters per position**.
|
||||
- Password length: 32 characters.
|
||||
|
||||
### 2.2. Total Keyspace
|
||||
The total number of possible passwords is calculated as:
|
||||
62^32 ≈ 1.46 × 10^57
|
||||
This means there are **1.46 decillion** possible combinations.
|
||||
|
||||
---
|
||||
|
||||
## 3. Brute-Force Resistance
|
||||
### 3.1. Average Number of Guesses
|
||||
On average, an attacker would need to try half of the keyspace to guess the correct password:
|
||||
(62^32) / 2 ≈ 7.3 × 10^56 attempts
|
||||
|
||||
### 3.2. Time to Crack on Modern Hardware
|
||||
| Hardware | Hashes per Second | Time to Exhaust Keyspace |
|
||||
|-------------------|-------------------|--------------------------------|
|
||||
| Modern CPU | 10 billion | 7.3 × 10^46 seconds | ≈ 2.3 × 10^39 years |
|
||||
| Modern GPU | 100 billion | 7.3 × 10^45 seconds | ≈ 2.3 × 10^38 years |
|
||||
|
||||
**Note**: Even with massive parallelization (e.g., botnets or supercomputers), brute-forcing a 32-character password from this keyspace is practically infeasible.
|
||||
|
||||
---
|
||||
|
||||
## 4. Comparison with Shorter Passwords
|
||||
| Length | Keyspace (62 Characters) | Average Guesses | Time on GPU (100 GigaHashes/s) |
|
||||
|--------|--------------------------|-----------------------|-------------------------------|
|
||||
| 16 | 4.7 × 10^28 | 2.35 × 10^28 | ~74 years |
|
||||
| 24 | 1.3 × 10^43 | 6.5 × 10^42 | ~2.1 million years |
|
||||
| 32 | 1.46 × 10^57 | 7.3 × 10^56 | ~2.3 trillion years |
|
||||
|
||||
---
|
||||
|
||||
## 5. Threat Model
|
||||
### 5.1. Brute-Force Attacks
|
||||
- **Conclusion**: Brute-force attacks are not a viable threat for 32-character passwords.
|
||||
- **Mitigation**: Ensure the system enforces rate-limiting to prevent automated guessing.
|
||||
|
||||
### 5.2. Social Engineering and Side-Channel Attacks
|
||||
- **Social Engineering**: Phishing, keyloggers, or shoulder surfing are more realistic threats than brute-force attacks.
|
||||
- **Side-Channel Attacks**: Timing attacks or power analysis could theoretically reduce security if the password verification is poorly implemented.
|
||||
- **Mitigation**: Use constant-time comparison functions for password verification.
|
||||
|
||||
### 5.3. Password Storage
|
||||
- **Hashing**: Always store passwords using strong, adaptive hashing algorithms like:
|
||||
- Argon2 (recommended for new systems)
|
||||
- bcrypt or PBKDF2 (with high work factors)
|
||||
- **Salting**: Use a unique salt per password to prevent rainbow table attacks.
|
||||
|
||||
---
|
||||
|
||||
## 6. Practical Recommendations
|
||||
### 6.1. For Users
|
||||
- **Password Managers**: Encourage the use of password managers to store and manage generated passwords.
|
||||
- **Multi-Factor Authentication (MFA)**: Always enable MFA where possible to add an extra layer of security.
|
||||
|
||||
### 6.2. For Developers
|
||||
- **Rate Limiting**: Implement rate limiting on authentication endpoints to slow down brute-force attempts.
|
||||
- **Secure Transmission**: Ensure passwords are transmitted over TLS/SSL to prevent interception.
|
||||
- **Password Policies**: Enforce policies that discourage password reuse and encourage regular updates.
|
||||
|
||||
### 6.3. For DFIR and Incident Response
|
||||
- **Logging and Monitoring**: Log failed login attempts and monitor for unusual activity.
|
||||
- **Incident Response Plan**: Have a plan in place for compromised accounts, including forced password resets and user notification.
|
||||
|
||||
---
|
||||
|
||||
## 7. Additional Considerations
|
||||
### 7.1. Extended Character Set
|
||||
If special characters are included (e.g., !@#$%^&*), the keyspace increases to:
|
||||
72^32 ≈ 1.9 × 10^60
|
||||
This further improves security but is not necessary for most use cases given the already massive keyspace.
|
||||
|
||||
### 7.2. Entropy Calculation
|
||||
The entropy of a 32-character password from a 62-character set is:
|
||||
log2(62^32) ≈ 192.6 bits
|
||||
This exceeds the 128-bit security level recommended by NIST for cryptographic applications.
|
||||
|
||||
---
|
||||
|
||||
## 8. Conclusion
|
||||
The passwords generated by this application are extremely secure against brute-force attacks due to their length and character diversity. The primary risks lie in human factors (e.g., phishing, reuse) and implementation flaws (e.g., weak hashing, lack of rate limiting).
|
||||
|
||||
For DFIR and high-security environments, combine these passwords with:
|
||||
- Multi-Factor Authentication (MFA)
|
||||
- Regular audits of authentication logs
|
||||
- User education on social engineering risks
|
||||
|
||||
---
|
||||
|
||||
## 9. References
|
||||
- [NIST Special Publication 800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html) (Digital Identity Guidelines)
|
||||
- [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
|
||||
- [Argon2: The Memory-Hard Function for Password Hashing](https://github.com/P-H-C/phc-winner-argon2)
|
||||
|
||||
BIN
img/screenshot.png
Normal file
BIN
img/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
28
main.go
28
main.go
@@ -9,8 +9,22 @@ import (
|
||||
|
||||
const (
|
||||
passwordLength = 32
|
||||
// Zeichensatz mit 62 möglichen Zeichen pro Position
|
||||
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
//chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!?$%&=#+<>-:,.;_*@"
|
||||
|
||||
// Zeichensatz mit 58 möglichen Zeichen pro Position
|
||||
// Verwechslungsanfällige Zeichen (0, O, 1, l, I) sind nicht enthalten.
|
||||
//
|
||||
// ## Security Note: ################################################
|
||||
// Der reduzierte Zeichensatz setzt den Keyspace von 10^57 auf 10^56 herab.
|
||||
// Die Entropie wird von ~192.6 Bit auf ~190.6 Bit herabgesetzt.
|
||||
// Solange die Passwortlänge von 32 Zeichen beibehalten wird ist der
|
||||
// Sicherheitsverlust durch einen reduzierten Zeichensatz akzeptabel,
|
||||
// weil der Keyspace immer noch so groß ist dass ein erraten praktisch
|
||||
// unmöglich ist.
|
||||
//
|
||||
//const chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789"
|
||||
|
||||
)
|
||||
|
||||
func generatePassword() string {
|
||||
@@ -182,6 +196,17 @@ html := fmt.Sprintf(
|
||||
.renew-button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
.about-link {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
font-size: 1.2rem;
|
||||
color: #999;
|
||||
text-decoration: none;
|
||||
}
|
||||
.about-link:hover {
|
||||
color: #444;
|
||||
}
|
||||
.help-link {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
@@ -218,6 +243,7 @@ html := fmt.Sprintf(
|
||||
<body>
|
||||
<div class="container">
|
||||
<a href="/help" class="help-link">API</a>
|
||||
<a class="about-link" href="https://gitea.scu.si/FlorianWalther/Web-Password">code</a>
|
||||
<h1>Generiertes Passwort</h1>
|
||||
<div id="password">%s</div>
|
||||
<div class="buttons">
|
||||
|
||||
45
misc/MoreUsage.md
Normal file
45
misc/MoreUsage.md
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
|
||||
# Baue die Go-Anwendung
|
||||
|
||||
```
|
||||
go build -o password-generator ./
|
||||
```
|
||||
|
||||
# Baue das Docker-Image
|
||||
|
||||
```
|
||||
docker build -t password-generator .
|
||||
```
|
||||
|
||||
# Starte den Docker Container
|
||||
|
||||
```
|
||||
docker run -p 8080:8080 password-generator
|
||||
```
|
||||
|
||||
## mit docker-compose
|
||||
|
||||
Ein `docker-compose.yml` wird mitgeliefert.
|
||||
|
||||
### initial pull
|
||||
|
||||
```
|
||||
docker compose login gitea.scu.si
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
### start up
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### bring down
|
||||
|
||||
```
|
||||
docker compose down
|
||||
```
|
||||
|
||||
|
||||
|
||||
24
misc/docker-compose.traefik.yml
Normal file
24
misc/docker-compose.traefik.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
services:
|
||||
password-generator:
|
||||
image: gitea.scu.si/florianwalther/password-generator:latest
|
||||
container_name: password-generator
|
||||
restart: always
|
||||
expose:
|
||||
- "8080:8080"
|
||||
# Falls die Registry privat ist, muss der Host zuvor mit
|
||||
# 'docker login gitea.scu.si' angemeldet worden sein.
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_backend"
|
||||
- "traefik.http.routers.webpass.rule=Host(`passwd.scu.si`)"
|
||||
- "traefik.http.routers.webpass.entrypoints=web,websecure"
|
||||
- "traefik.http.routers.webpass.tls=true"
|
||||
- "traefik.http.routers.webpass.tls.certresolver=myresolver"
|
||||
- "traefik.http.services.webpass.loadbalancer.server.port=8080"
|
||||
networks:
|
||||
- traefik_backend
|
||||
|
||||
networks:
|
||||
traefik_backend:
|
||||
external: true
|
||||
|
||||
9
misc/docker-compose.yml
Normal file
9
misc/docker-compose.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
services:
|
||||
password-generator:
|
||||
image: gitea.scu.si/florianwalther/password-generator:latest
|
||||
container_name: password-generator
|
||||
restart: always
|
||||
ports:
|
||||
- "8080:8080"
|
||||
# Falls die Registry privat ist, muss der Host zuvor mit
|
||||
# 'docker login gitea.scu.si' angemeldet worden sein.
|
||||
Reference in New Issue
Block a user