Mit første naive forsøg på at forhindre kriminelles brug af lnk.dk til at pege på diverse phishing-sider lykkedes, mildt sagt, ikke.
Nu har jeg taget skrappere midler i brug.
I min models.py i min Django-applikation, tilføjer jeg et felt til at gemme ip-adresse på den, der har oprettet et link, og et felt til at markere, om et link er usikkert:
class Link(models.Model):
# Short link is only lower case
def save(self, *args, **kwargs):
self.shortlink = self.shortlink.lower()
return super(Link, self).save(*args, **kwargs)
destination = models.URLField('Destinationslink', max_length=65535, validators=[validate_destination])
shortlink = models.SlugField('Kort link', max_length=100, unique=True, allow_unicode=False, validators=[validate_shortlink])
LINK_TYPE_CHOICES = (
('automatic', 'Automatisk'),
('manual', 'Manuelt'),
)
submitter_ip = models.GenericIPAddressField(null=True)
unsafe_link = models.BooleanField(default=False)
type = models.CharField('Type', max_length=10, choices=LINK_TYPE_CHOICES)
date = models.DateTimeField(default=timezone.now, editable=False)
Derudover tilføjer jeg tabeller til at kunne blokere for ip-adresser og domæner, der ikke skal kunne oprette brugbare links:
class Ban(models.Model):
banned_ip = models.GenericIPAddressField(unique=True)
class BanDomain(models.Model):
banned_domain = models.CharField(max_length=255, unique=True)
Med det på plads tilpasser jeg min logik til oprettelse af links i views.py sådan, at:
- kun brugere med ip-adresser kan oprette links,
- links bliver tjekket med Google Safe Browsing (efter råd på Twitter)
- links til domæner og fra ip-adresser, der er blokeret, bliver automatisk markeret som usikre
Her er funktionen til at tjekke links op mod Google Safe Browsing:
# Google safe browsing API check function
def is_url_google_safe_browsing_safe(url):
params = {
'key': ''
}
json = {
"client": {
"clientId": "lnk.dk",
"clientVersion": "1.0"
},
"threatInfo": {
"threatTypes": ["MALWARE", "SOCIAL_ENGINEERING", "UNWANTED_SOFTWARE"],
"platformTypes": ["ANY_PLATFORM"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": url}
]
}
}
api_url = 'https://safebrowsing.googleapis.com/v4/threatMatches:find'
try:
response_json = requests.post(api_url, params=params, json=json).json()
if response_json:
return True
else:
return False
# If something unexpected is returned from Google, link creation is allowed
except:
return False
Og her er min nye logik til at tjekke modtagne links. Læg mærke til, at brugere uden ip-adresse automatisk bliver rickrolled
if form.is_valid():
client_ip, is_routable = get_client_ip(request)
# Hiding your IP seems illegit, so user is rickrolled
if client_ip is None:
return HttpResponseRedirect('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
else:
destination = form.cleaned_data['destination'] # Submitted destination
shortlink = form.cleaned_data['shortlink'] # Submitted slug
# Google Safe Browsing check
unsafe_url = is_url_google_safe_browsing_safe(destination)
# Ban domain check
domain_info = extract(destination)
domain = domain_info.domain + '.' + domain_info.suffix
domain_ban = BanDomain.objects.filter(banned_domain=domain)
if len(domain_ban) > 0:
banned_domain = True
else:
banned_domain = False
# Ban ip check
ip_ban = Ban.objects.filter(banned_ip=client_ip)
if len(ip_ban) > 0:
banned_ip = True
else:
banned_ip = False
Til sidst har jeg forsøgt at narre phisherne ved at links til usikre sider virker, for den, der selv har oprettet linket. Alle andre bliver rickrollet, hvis de klikker på et usikkert link:
# Short link redirect to destination URL
def redirect(request, shortlink):
# Query the database for short link, if there is a hit, redirect to destination URL
# In case of uppercase characters in user input shortlink, the link is made lowercase
# Also, check if ip is banned
try:
client_ip, is_routable = get_client_ip(request)
link = Link.objects.get(shortlink=shortlink.lower())
# Legit users are rickrolled when an unsafe link is visited from an IP that is not banned
if link.unsafe_link == True and not client_ip == link.submitter_ip:
return HttpResponseRedirect('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
# For safe links AND for unsafe links visited from banned IPs, user is redirected to destination
else:
# If there's a referer and it's the same as the destination link, show a 404 to avoid an endless loop
if 'HTTP_REFERER' in request.META and link.destination == request.META['HTTP_REFERER']:
return render(request, 'links/404.html', status=404)
return HttpResponseRedirect(link.destination)
# In case of an error, show 404 page
except:
return render(request, 'links/404.html', status=404)