Καλήσπέρα στην κοινότητα,
Αφού είδα το συγκεκριμένο βίντεο από το κανάλι computerphile στο yt : https://www.youtube.com/watch?v=hhUb5iknVJs
έγραψα το συγκεκριμένο πρόγραμμα σε python3 το οποίο ελέγχει τοπικά αν έχει “αλιευτεί” το password μας, με βάση την ιστοσελίδα have i been pwned(https://haveibeenpwned.com/). Το συγκεκριμένο πρόγραμμα κατεβάζει λίστα σε μορφή txt αρχείου και ελέγχει αν υπάρχει στην λίστα το password μας, χωρίς να υποβάλλει τον κωδικό στο site(γι’ αυτό αναφέρουμε την λέξη *τοπικά). Αντίστοιχο πρόγραμμα έφτιαξε και ο τύπος του βίντεο, το οποίο μπορούμε να βρούμε εδώ : https://github.com/mikepound/pwned-search.
Ο κώδικας του προγράμματος μου είναι ο εξής :
#!/usr/bin/env python
import hashlib
import requests
import urllib
password=str(raw_input('Give password : '))
hashedpass=hashlib.sha1(password.encode())
hexpass=hashedpass.hexdigest()
stripped=hexpass[0:5]
link='https://api.pwnedpasswords.com/range/'+stripped
list=requests.get(link)
f = open(“list.txt”,“w”)
f.write(list.text)
f.close
f = open(“list.txt”,“r”)
for line in f:
if hexpass[6:].upper() in line:
print line
f.close
Οποιεσδήποτε διορθώσεις ή απορίες είναι καλοδεχούμενες!
Μπράβο!
Τις προάλλες, είχα μπει στο site, και λέω καλά…σε ρωτάει “τσέκαρε αν ο κωδικός σου είναι χακαρισμένος”, και εσύ πας και τον βάζεις;;; Κι αν αυτός που έχει κάνει το site κρατάει λεξικό με εκατομμύρια κωδικούς, και το δίνει όπου θέλει κατά το δοκούν, ποιος τον ελέγχει;…
Και σκεφτόμουν αυτή ακριβώς την ανάγκη, ο όποιος έλεγχος να γίνεται off-line!
Μπράβο και πάλι για την σκέψη, και την υλοποίηση!!!
Εμένα πλέον στο ίντερνετ δεν μου φαίνεται τίποτα περίεργο. Δες εδώ κωδικό 12345 εν έτη 2019, 2.380.800 άτομα. Ο ανθρώπινος παράγοντας θα είναι πάντα μια τρύπα ασφαλείας ότι και να κάνεις.
Ξεκινάμε με το προφανές, ότι το πρόγραμμα που έγραψες ΔΕΝ είναι python3 :D
Επίσης δεν έχεις σωστά τα indentations και δε δουλεύει ο κώδικας
Τέλος να βάζεις τον κώδικα σε code tags
Μια βελτιωμένη έκδοση με μήνυμα λάθους
#!/usr/bin/env python
import hashlib
import requests
import urllib
password=str(input('Give password : '))
hashedpass=hashlib.sha1(password.encode())
hexpass=hashedpass.hexdigest()
stripped=hexpass[0:5]
link='https://api.pwnedpasswords.com/range/'+stripped
list=requests.get(link)
f = open('list.txt','w')
f.write(list.text)
f.close
f = open('list.txt','r')
status="0"
for line in f:
if hexpass[6:].upper() in line:
status=line+"\nΟ Κωδικός έχει διαρεύσει"
if status=="0":
print("Ο Κωδικός ΔΕΝ έχει διαρεύσει")
else:
print(status)
Επίσης μια καλή προσθήκη θα ήταν να βγαίνει ο κωδικός που εισάγεται με αστεράκια για λόγους ασφαλείας.
Επίσης, αντί να βάζεις τον κώδικα σε code tags, τα οποία μάλλον εδώ δε διαθέτουν syntax highlighting, μπορείς να χρησιμοποιείς την ακόλουθη σύνταξη, ώστε να είναι πιο ευανάγνωστος ο κώδικας σου:
```<γλώσσα π.χ. python>
code here
```
Ας πούμε, για τον κώδικα του νήματος που έγραψε ο @Maras:
#!/usr/bin/env python
import hashlib
import requests
import urllib
password=str(input('Give password : '))
hashedpass=hashlib.sha1(password.encode())
hexpass=hashedpass.hexdigest()
stripped=hexpass[0:5]
link='https://api.pwnedpasswords.com/range/'+stripped
list=requests.get(link)
f = open('list.txt','w')
f.write(list.text)
f.close
f = open('list.txt','r')
status="0"
for line in f:
if hexpass[6:].upper() in line:
status=line+"\nΟ Κωδικός έχει διαρεύσει"
if status=="0":
print("Ο Κωδικός ΔΕΝ έχει διαρεύσει")
else:
print(status)
Δυστυχώς, o editor για τις απαντήσεις σε νήματα, τουλάχιστον για εμένα, δεν χρησιμοποιεί αυτή τη σύνταξη για τον κώδικα (αν και θα έπρεπε).
Το παραπάνω είναι μια απο τις δυνατότητες μίας γλώσσας, ιδιαίτερης εκφραστικότητας, η οποία ονομάζεται Markdown, και υποστηρίζεται σε κάποιον βαθμό από την πλατφόρμα που τρέχει το φορουμ.
Μετά τις χρήσιμες προσθήκες και αναφορές του @billniakas και του @arvchristos, στο πρόγραμμα δεν φαίνεται η πληκτρολόγηση του κωδικού (μένει κενό το πεδίο, χωρίς βέβαια να φαίνεται πόσους χαρακτήρες πληκτρολογούμε) με την χρήση του getpass module.
Επίσης αν είναι να χρησιμοποιήσουμε ελληνικούς χαρακτήρες για τα μηνύματα θα πρέπει να δηλώσουμε και το αντίστοιχο encoding(utf-8 στην περίπτωση μας).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hashlib
import requests
import urllib
from getpass import getpass
password=getpass('Give password : ')
hashedpass=hashlib.sha1(password.encode())
hexpass=hashedpass.hexdigest()
stripped=hexpass[0:5]
link='https://api.pwnedpasswords.com/range/'+stripped
list=requests.get(link)
f = open('list.txt','w')
f.write(list.text)
f.close
f = open('list.txt','r')
status="0"
for line in f:
if hexpass[6:].upper() in line:
status=line+"\nΟ Κωδικός έχει διαρεύσει"
if status=="0":
print("Ο Κωδικός ΔΕΝ έχει διαρεύσει")
else:
print(status)
@billniakas θα το ψάξω αν μπορεί να βγάζει αστερίσκους
Σκεφτόμουν να φτιάξω ένα ολόκληρο εργαλείο για αυτό και να το βάλω στο Google Home να μου λεει καθε μερα τι παίζει με τον λογαριασμό μου αλλά θέλουν 3.5 Ευρώ τον μήνα … https://haveibeenpwned.com/API/Key
Τους κωδικους μπορείς να τους ελέγχω χωρίς να χρειάζεται καποιο token. πχ έγγραψα το παρακάτω script σε Go να κάνει ακριβώς αυτό:
package main
import (
"crypto/sha1"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
)
// passToHash() encrypts your "password" with SHA-1 and returns it in hex
func passToHash(password string) string {
hash := sha1.New() // Returns a new hash.Hash computing the SHA1 checksum
hash.Write([]byte(password)) // `Write` expects bytes
byteHash := hash.Sum(nil) // This gets the finalized hash result as a byte slice uint8
hexHash := fmt.Sprintf("%x", byteHash) // Use the `%x` format verb to convert a hash results to a hex string
hexHash = strings.ToUpper(hexHash) // Make the hash upper case
return hexHash
}
// getPassList() fetches the API response and and error in case of a problem
// Read: https://haveibeenpwned.com/API/v3#SearchingPwnedPasswordsByRange
func getPassList(hash string) ([]string, error) {
APIURL := fmt.Sprintf("%s%s", "https://api.pwnedpasswords.com/range/", hash)
// Construct a *http.Request with a GET method against the APIURL
req, err := http.NewRequest(http.MethodGet, APIURL, nil)
if err != nil {
return nil, err
}
// Create an HTTP Client to handle this *http.Request
client := http.DefaultClient
// Make the actual request using the client and get server's *http.Response
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// Read only the body part of the *http.Response (as an array of bytes)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
bodyStr := fmt.Sprintf("%#v", string(body)) // Convert bytes into string
// Split the body string into sub-strings on every carriage return and newline character
// creating an array of strings (password hashes)
bodyStrArray := strings.Split(bodyStr, `\r\n`)
return bodyStrArray, nil
}
// isPwned() checks if your "pass" is included in the "list" of pwned password
// and it returns how many times it has been hacked
func isPwned(list []string, pass string) (bool, string) {
for _, value := range list {
if strings.Contains(value, pass) {
return true, value
}
}
return false, ""
}
func main() {
password := os.Args[1] // Use the first positional parameter as the password
// Calculate the SHA-1 hash of your password
hash := passToHash(password)
// Query they API using the first 5 characters of it
passList, err := getPassList(hash[0:5])
if err != nil {
log.Fatal(err)
}
// Test (locally) if your password is hacked by passing the rest of it
pwned, result := isPwned(passList, hash[5:])
if pwned {
s := strings.Split(result, ":")
times := s[1] // isolate the part after the ':'
fmt.Printf("Your password have been PWNED %s times\n", times)
} else {
fmt.Printf("You are not PWNED\n")
}
}
Output:
$ pwnedpass 123456
Your password have been PWNED 23547453 times
$ pwnedpass lkjdfuiusoiuf9ph34lksfsldf
You are not PWNED
Για τα υπόλοιπα API calls (πχ όπως αυτό που χρειάζονται e-mail address τα έχει κλειδωμένα. Για παράδειγμα, δοκιμαζοντας στον browser το e-mail μου, πετάει:
{ "statusCode": 401, "message": "Access denied due to missing hibp-api-key." }
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hashlib
import requests
import urllib
import getch
import sys
from getpass import getpass
def readLineWithAsterisks():
sBuffer = ''
while True:
c = getch.getch()
if c == '\n':
return sBuffer
elif ord(c) == 127:
if len(sBuffer) > 0:
sys.stdout.write('\x08 \x08')
sys.stdout.flush()
sBuffer = sBuffer[0:-1]
continue
else:
sys.stdout.write('*')
sys.stdout.flush()
sBuffer += c
print "Give password : "
password=readLineWithAsterisks()
hashedpass=hashlib.sha1(password.encode())
hexpass=hashedpass.hexdigest()
stripped=hexpass[0:5]
link='https://api.pwnedpasswords.com/range/'+stripped
list=requests.get(link)
f = open('list.txt','w')
f.write(list.text)
f.close
f = open('list.txt','r')
status="0"
for line in f:
if hexpass[6:].upper() in line:
status=line+"\nΟ Κωδικός έχει διαρεύσει"
if status=="0":
print("Ο Κωδικός ΔΕΝ έχει διαρεύσει")
else:
print(status)
@billniakas απλά με τους αστερίσκους, φαίνεται ο αριθμός των χαρακτήρων του κωδικού…(ίσως το να μην βγάζει τίποτα, όταν πληκτρολογούμε, είναι καλύτερη λύση).