mstkyvz commited on
Commit
56ca4c1
1 Parent(s): ca4ef78

Upload 4 files

Browse files
Files changed (4) hide show
  1. app.py +38 -0
  2. feature.py +489 -0
  3. model.pkl +3 -0
  4. templates/index.html +102 -0
app.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, render_template
2
+ import numpy as np
3
+ import pickle
4
+ import warnings
5
+
6
+ warnings.filterwarnings('ignore')
7
+ from feature import FeatureExtraction
8
+
9
+
10
+ file = open("model.pkl", "rb")
11
+ gbc = pickle.load(file)
12
+
13
+ app = Flask(__name__)
14
+
15
+ @app.route('/', methods=['GET', 'POST'])
16
+ def index():
17
+ result = None
18
+ result_class = None
19
+ url = None
20
+ if request.method == 'POST':
21
+ url = request.form['url']
22
+ obj = FeatureExtraction(url)
23
+ x = np.array(obj.getFeaturesList()).reshape(1, 30)
24
+
25
+ y_pred = gbc.predict(x)[0]
26
+ y_pro_phishing = gbc.predict_proba(x)[0, 0]
27
+ y_pro_non_phishing = gbc.predict_proba(x)[0, 1]
28
+
29
+ if y_pred == 1:
30
+ result = "It is {0:.2f}% safe to go".format(y_pro_non_phishing * 100)
31
+ result_class = "safe"
32
+ else:
33
+ result = "It is {0:.2f}% phishing".format(y_pro_phishing * 100)
34
+ result_class = "phishing"
35
+
36
+ return render_template('index.html', result=result, url=url, result_class=result_class)
37
+ if __name__ == '__main__':
38
+ app.run(debug=True)
feature.py ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ipaddress
2
+ import re
3
+ import urllib.request
4
+ from bs4 import BeautifulSoup
5
+ import socket
6
+ import requests
7
+ from googlesearch import search
8
+ import whois
9
+ from datetime import date, datetime
10
+ import time
11
+ from dateutil.parser import parse as date_parse
12
+ from urllib.parse import urlparse
13
+
14
+ class FeatureExtraction:
15
+ features = []
16
+ def __init__(self,url):
17
+ self.features = []
18
+ self.url = url
19
+ self.domain = ""
20
+ self.whois_response = ""
21
+ self.urlparse = ""
22
+ self.response = ""
23
+ self.soup = ""
24
+
25
+ try:
26
+ self.response = requests.get(url)
27
+ self.soup = BeautifulSoup(response.text, 'html.parser')
28
+ except:
29
+ pass
30
+
31
+ try:
32
+ self.urlparse = urlparse(url)
33
+ self.domain = self.urlparse.netloc
34
+ except:
35
+ pass
36
+
37
+ try:
38
+ self.whois_response = whois.whois(self.domain)
39
+ except:
40
+ pass
41
+
42
+
43
+
44
+
45
+ self.features.append(self.UsingIp())
46
+ self.features.append(self.longUrl())
47
+ self.features.append(self.shortUrl())
48
+ self.features.append(self.symbol())
49
+ self.features.append(self.redirecting())
50
+ self.features.append(self.prefixSuffix())
51
+ self.features.append(self.SubDomains())
52
+ self.features.append(self.Hppts())
53
+ self.features.append(self.DomainRegLen())
54
+ self.features.append(self.Favicon())
55
+
56
+
57
+ self.features.append(self.NonStdPort())
58
+ self.features.append(self.HTTPSDomainURL())
59
+ self.features.append(self.RequestURL())
60
+ self.features.append(self.AnchorURL())
61
+ self.features.append(self.LinksInScriptTags())
62
+ self.features.append(self.ServerFormHandler())
63
+ self.features.append(self.InfoEmail())
64
+ self.features.append(self.AbnormalURL())
65
+ self.features.append(self.WebsiteForwarding())
66
+ self.features.append(self.StatusBarCust())
67
+
68
+ self.features.append(self.DisableRightClick())
69
+ self.features.append(self.UsingPopupWindow())
70
+ self.features.append(self.IframeRedirection())
71
+ self.features.append(self.AgeofDomain())
72
+ self.features.append(self.DNSRecording())
73
+ self.features.append(self.WebsiteTraffic())
74
+ self.features.append(self.PageRank())
75
+ self.features.append(self.GoogleIndex())
76
+ self.features.append(self.LinksPointingToPage())
77
+ self.features.append(self.StatsReport())
78
+
79
+
80
+ # 1.UsingIp
81
+ def UsingIp(self):
82
+ try:
83
+ ipaddress.ip_address(self.url)
84
+ return -1
85
+ except:
86
+ return 1
87
+
88
+ # 2.longUrl
89
+ def longUrl(self):
90
+ if len(self.url) < 54:
91
+ return 1
92
+ if len(self.url) >= 54 and len(self.url) <= 75:
93
+ return 0
94
+ return -1
95
+
96
+ # 3.shortUrl
97
+ def shortUrl(self):
98
+ match = re.search('bit\.ly|goo\.gl|shorte\.st|go2l\.ink|x\.co|ow\.ly|t\.co|tinyurl|tr\.im|is\.gd|cli\.gs|'
99
+ 'yfrog\.com|migre\.me|ff\.im|tiny\.cc|url4\.eu|twit\.ac|su\.pr|twurl\.nl|snipurl\.com|'
100
+ 'short\.to|BudURL\.com|ping\.fm|post\.ly|Just\.as|bkite\.com|snipr\.com|fic\.kr|loopt\.us|'
101
+ 'doiop\.com|short\.ie|kl\.am|wp\.me|rubyurl\.com|om\.ly|to\.ly|bit\.do|t\.co|lnkd\.in|'
102
+ 'db\.tt|qr\.ae|adf\.ly|goo\.gl|bitly\.com|cur\.lv|tinyurl\.com|ow\.ly|bit\.ly|ity\.im|'
103
+ 'q\.gs|is\.gd|po\.st|bc\.vc|twitthis\.com|u\.to|j\.mp|buzurl\.com|cutt\.us|u\.bb|yourls\.org|'
104
+ 'x\.co|prettylinkpro\.com|scrnch\.me|filoops\.info|vzturl\.com|qr\.net|1url\.com|tweez\.me|v\.gd|tr\.im|link\.zip\.net', self.url)
105
+ if match:
106
+ return -1
107
+ return 1
108
+
109
+ # 4.Symbol@
110
+ def symbol(self):
111
+ if re.findall("@",self.url):
112
+ return -1
113
+ return 1
114
+
115
+ # 5.Redirecting//
116
+ def redirecting(self):
117
+ if self.url.rfind('//')>6:
118
+ return -1
119
+ return 1
120
+
121
+ # 6.prefixSuffix
122
+ def prefixSuffix(self):
123
+ try:
124
+ match = re.findall('\-', self.domain)
125
+ if match:
126
+ return -1
127
+ return 1
128
+ except:
129
+ return -1
130
+
131
+ # 7.SubDomains
132
+ def SubDomains(self):
133
+ dot_count = len(re.findall("\.", self.url))
134
+ if dot_count == 1:
135
+ return 1
136
+ elif dot_count == 2:
137
+ return 0
138
+ return -1
139
+
140
+ # 8.HTTPS
141
+ def Hppts(self):
142
+ try:
143
+ https = self.urlparse.scheme
144
+ if 'https' in https:
145
+ return 1
146
+ return -1
147
+ except:
148
+ return 1
149
+
150
+ # 9.DomainRegLen
151
+ def DomainRegLen(self):
152
+ try:
153
+ expiration_date = self.whois_response.expiration_date
154
+ creation_date = self.whois_response.creation_date
155
+ try:
156
+ if(len(expiration_date)):
157
+ expiration_date = expiration_date[0]
158
+ except:
159
+ pass
160
+ try:
161
+ if(len(creation_date)):
162
+ creation_date = creation_date[0]
163
+ except:
164
+ pass
165
+
166
+ age = (expiration_date.year-creation_date.year)*12+ (expiration_date.month-creation_date.month)
167
+ if age >=12:
168
+ return 1
169
+ return -1
170
+ except:
171
+ return -1
172
+
173
+ # 10. Favicon
174
+ def Favicon(self):
175
+ try:
176
+ for head in self.soup.find_all('head'):
177
+ for head.link in self.soup.find_all('link', href=True):
178
+ dots = [x.start(0) for x in re.finditer('\.', head.link['href'])]
179
+ if self.url in head.link['href'] or len(dots) == 1 or domain in head.link['href']:
180
+ return 1
181
+ return -1
182
+ except:
183
+ return -1
184
+
185
+ # 11. NonStdPort
186
+ def NonStdPort(self):
187
+ try:
188
+ port = self.domain.split(":")
189
+ if len(port)>1:
190
+ return -1
191
+ return 1
192
+ except:
193
+ return -1
194
+
195
+ # 12. HTTPSDomainURL
196
+ def HTTPSDomainURL(self):
197
+ try:
198
+ if 'https' in self.domain:
199
+ return -1
200
+ return 1
201
+ except:
202
+ return -1
203
+
204
+ # 13. RequestURL
205
+ def RequestURL(self):
206
+ try:
207
+ for img in self.soup.find_all('img', src=True):
208
+ dots = [x.start(0) for x in re.finditer('\.', img['src'])]
209
+ if self.url in img['src'] or self.domain in img['src'] or len(dots) == 1:
210
+ success = success + 1
211
+ i = i+1
212
+
213
+ for audio in self.soup.find_all('audio', src=True):
214
+ dots = [x.start(0) for x in re.finditer('\.', audio['src'])]
215
+ if self.url in audio['src'] or self.domain in audio['src'] or len(dots) == 1:
216
+ success = success + 1
217
+ i = i+1
218
+
219
+ for embed in self.soup.find_all('embed', src=True):
220
+ dots = [x.start(0) for x in re.finditer('\.', embed['src'])]
221
+ if self.url in embed['src'] or self.domain in embed['src'] or len(dots) == 1:
222
+ success = success + 1
223
+ i = i+1
224
+
225
+ for iframe in self.soup.find_all('iframe', src=True):
226
+ dots = [x.start(0) for x in re.finditer('\.', iframe['src'])]
227
+ if self.url in iframe['src'] or self.domain in iframe['src'] or len(dots) == 1:
228
+ success = success + 1
229
+ i = i+1
230
+
231
+ try:
232
+ percentage = success/float(i) * 100
233
+ if percentage < 22.0:
234
+ return 1
235
+ elif((percentage >= 22.0) and (percentage < 61.0)):
236
+ return 0
237
+ else:
238
+ return -1
239
+ except:
240
+ return 0
241
+ except:
242
+ return -1
243
+
244
+ # 14. AnchorURL
245
+ def AnchorURL(self):
246
+ try:
247
+ i,unsafe = 0,0
248
+ for a in self.soup.find_all('a', href=True):
249
+ if "#" in a['href'] or "javascript" in a['href'].lower() or "mailto" in a['href'].lower() or not (url in a['href'] or self.domain in a['href']):
250
+ unsafe = unsafe + 1
251
+ i = i + 1
252
+
253
+ try:
254
+ percentage = unsafe / float(i) * 100
255
+ if percentage < 31.0:
256
+ return 1
257
+ elif ((percentage >= 31.0) and (percentage < 67.0)):
258
+ return 0
259
+ else:
260
+ return -1
261
+ except:
262
+ return -1
263
+
264
+ except:
265
+ return -1
266
+
267
+ # 15. LinksInScriptTags
268
+ def LinksInScriptTags(self):
269
+ try:
270
+ i,success = 0,0
271
+
272
+ for link in self.soup.find_all('link', href=True):
273
+ dots = [x.start(0) for x in re.finditer('\.', link['href'])]
274
+ if self.url in link['href'] or self.domain in link['href'] or len(dots) == 1:
275
+ success = success + 1
276
+ i = i+1
277
+
278
+ for script in self.soup.find_all('script', src=True):
279
+ dots = [x.start(0) for x in re.finditer('\.', script['src'])]
280
+ if self.url in script['src'] or self.domain in script['src'] or len(dots) == 1:
281
+ success = success + 1
282
+ i = i+1
283
+
284
+ try:
285
+ percentage = success / float(i) * 100
286
+ if percentage < 17.0:
287
+ return 1
288
+ elif((percentage >= 17.0) and (percentage < 81.0)):
289
+ return 0
290
+ else:
291
+ return -1
292
+ except:
293
+ return 0
294
+ except:
295
+ return -1
296
+
297
+ # 16. ServerFormHandler
298
+ def ServerFormHandler(self):
299
+ try:
300
+ if len(self.soup.find_all('form', action=True))==0:
301
+ return 1
302
+ else :
303
+ for form in self.soup.find_all('form', action=True):
304
+ if form['action'] == "" or form['action'] == "about:blank":
305
+ return -1
306
+ elif self.url not in form['action'] and self.domain not in form['action']:
307
+ return 0
308
+ else:
309
+ return 1
310
+ except:
311
+ return -1
312
+
313
+ # 17. InfoEmail
314
+ def InfoEmail(self):
315
+ try:
316
+ if re.findall(r"[mail\(\)|mailto:?]", self.soap):
317
+ return -1
318
+ else:
319
+ return 1
320
+ except:
321
+ return -1
322
+
323
+ # 18. AbnormalURL
324
+ def AbnormalURL(self):
325
+ try:
326
+ if self.response.text == self.whois_response:
327
+ return 1
328
+ else:
329
+ return -1
330
+ except:
331
+ return -1
332
+
333
+ # 19. WebsiteForwarding
334
+ def WebsiteForwarding(self):
335
+ try:
336
+ if len(self.response.history) <= 1:
337
+ return 1
338
+ elif len(self.response.history) <= 4:
339
+ return 0
340
+ else:
341
+ return -1
342
+ except:
343
+ return -1
344
+
345
+ # 20. StatusBarCust
346
+ def StatusBarCust(self):
347
+ try:
348
+ if re.findall("<script>.+onmouseover.+</script>", self.response.text):
349
+ return 1
350
+ else:
351
+ return -1
352
+ except:
353
+ return -1
354
+
355
+ # 21. DisableRightClick
356
+ def DisableRightClick(self):
357
+ try:
358
+ if re.findall(r"event.button ?== ?2", self.response.text):
359
+ return 1
360
+ else:
361
+ return -1
362
+ except:
363
+ return -1
364
+
365
+ # 22. UsingPopupWindow
366
+ def UsingPopupWindow(self):
367
+ try:
368
+ if re.findall(r"alert\(", self.response.text):
369
+ return 1
370
+ else:
371
+ return -1
372
+ except:
373
+ return -1
374
+
375
+ # 23. IframeRedirection
376
+ def IframeRedirection(self):
377
+ try:
378
+ if re.findall(r"[<iframe>|<frameBorder>]", self.response.text):
379
+ return 1
380
+ else:
381
+ return -1
382
+ except:
383
+ return -1
384
+
385
+ # 24. AgeofDomain
386
+ def AgeofDomain(self):
387
+ try:
388
+ creation_date = self.whois_response.creation_date
389
+ try:
390
+ if(len(creation_date)):
391
+ creation_date = creation_date[0]
392
+ except:
393
+ pass
394
+
395
+ today = date.today()
396
+ age = (today.year-creation_date.year)*12+(today.month-creation_date.month)
397
+ if age >=6:
398
+ return 1
399
+ return -1
400
+ except:
401
+ return -1
402
+
403
+ # 25. DNSRecording
404
+ def DNSRecording(self):
405
+ try:
406
+ creation_date = self.whois_response.creation_date
407
+ try:
408
+ if(len(creation_date)):
409
+ creation_date = creation_date[0]
410
+ except:
411
+ pass
412
+
413
+ today = date.today()
414
+ age = (today.year-creation_date.year)*12+(today.month-creation_date.month)
415
+ if age >=6:
416
+ return 1
417
+ return -1
418
+ except:
419
+ return -1
420
+
421
+ # 26. WebsiteTraffic
422
+ def WebsiteTraffic(self):
423
+ try:
424
+ rank = BeautifulSoup(urllib.request.urlopen("http://data.alexa.com/data?cli=10&dat=s&url=" + url).read(), "xml").find("REACH")['RANK']
425
+ if (int(rank) < 100000):
426
+ return 1
427
+ return 0
428
+ except :
429
+ return -1
430
+
431
+ # 27. PageRank
432
+ def PageRank(self):
433
+ try:
434
+ prank_checker_response = requests.post("https://www.checkpagerank.net/index.php", {"name": self.domain})
435
+
436
+ global_rank = int(re.findall(r"Global Rank: ([0-9]+)", rank_checker_response.text)[0])
437
+ if global_rank > 0 and global_rank < 100000:
438
+ return 1
439
+ return -1
440
+ except:
441
+ return -1
442
+
443
+
444
+ # 28. GoogleIndex
445
+ def GoogleIndex(self):
446
+ try:
447
+ site = search(self.url, 5)
448
+ if site:
449
+ return 1
450
+ else:
451
+ return -1
452
+ except:
453
+ return 1
454
+
455
+ # 29. LinksPointingToPage
456
+ def LinksPointingToPage(self):
457
+ try:
458
+ number_of_links = len(re.findall(r"<a href=", self.response.text))
459
+ if number_of_links == 0:
460
+ return 1
461
+ elif number_of_links <= 2:
462
+ return 0
463
+ else:
464
+ return -1
465
+ except:
466
+ return -1
467
+
468
+ # 30. StatsReport
469
+ def StatsReport(self):
470
+ try:
471
+ url_match = re.search(
472
+ 'at\.ua|usa\.cc|baltazarpresentes\.com\.br|pe\.hu|esy\.es|hol\.es|sweddy\.com|myjino\.ru|96\.lt|ow\.ly', url)
473
+ ip_address = socket.gethostbyname(self.domain)
474
+ ip_match = re.search('146\.112\.61\.108|213\.174\.157\.151|121\.50\.168\.88|192\.185\.217\.116|78\.46\.211\.158|181\.174\.165\.13|46\.242\.145\.103|121\.50\.168\.40|83\.125\.22\.219|46\.242\.145\.98|'
475
+ '107\.151\.148\.44|107\.151\.148\.107|64\.70\.19\.203|199\.184\.144\.27|107\.151\.148\.108|107\.151\.148\.109|119\.28\.52\.61|54\.83\.43\.69|52\.69\.166\.231|216\.58\.192\.225|'
476
+ '118\.184\.25\.86|67\.208\.74\.71|23\.253\.126\.58|104\.239\.157\.210|175\.126\.123\.219|141\.8\.224\.221|10\.10\.10\.10|43\.229\.108\.32|103\.232\.215\.140|69\.172\.201\.153|'
477
+ '216\.218\.185\.162|54\.225\.104\.146|103\.243\.24\.98|199\.59\.243\.120|31\.170\.160\.61|213\.19\.128\.77|62\.113\.226\.131|208\.100\.26\.234|195\.16\.127\.102|195\.16\.127\.157|'
478
+ '34\.196\.13\.28|103\.224\.212\.222|172\.217\.4\.225|54\.72\.9\.51|192\.64\.147\.141|198\.200\.56\.183|23\.253\.164\.103|52\.48\.191\.26|52\.214\.197\.72|87\.98\.255\.18|209\.99\.17\.27|'
479
+ '216\.38\.62\.18|104\.130\.124\.96|47\.89\.58\.141|78\.46\.211\.158|54\.86\.225\.156|54\.82\.156\.19|37\.157\.192\.102|204\.11\.56\.48|110\.34\.231\.42', ip_address)
480
+ if url_match:
481
+ return -1
482
+ elif ip_match:
483
+ return -1
484
+ return 1
485
+ except:
486
+ return 1
487
+
488
+ def getFeaturesList(self):
489
+ return self.features
model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9c2514edb88d1fbc8dd5b0a586537ed288c4331f50e4a983db4bcfb931cec80
3
+ size 225974
templates/index.html ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Web Phishing Detection</title>
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ padding: 0;
10
+ background: url('https://i.pinimg.com/originals/19/e1/71/19e171391727335f510db47a13269d2d.gif') no-repeat center center fixed;
11
+ background-size: cover;
12
+ font-family: 'Courier New', Courier, monospace;
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: center;
16
+ color: #0ff;
17
+ }
18
+
19
+ h1 {
20
+ border-bottom: 2px solid #0ff;
21
+ padding-bottom: 10px;
22
+ }
23
+
24
+ form {
25
+ display: flex;
26
+ flex-direction: column;
27
+ align-items: center;
28
+ justify-content: center;
29
+ padding: 20px;
30
+ border: 2px solid #0ff;
31
+ border-radius: 10px;
32
+ background-color: rgba(0, 0, 0, 0.6);
33
+ margin-top: 30px;
34
+ }
35
+
36
+ textarea, input[type="text"] {
37
+ width: 300px;
38
+ border: 2px solid #0ff;
39
+ background-color: rgba(0, 0, 0, 0.8);
40
+ color: #0ff;
41
+ padding: 10px;
42
+ border-radius: 5px;
43
+ font-family: 'Courier New', Courier, monospace;
44
+ }
45
+
46
+ textarea {
47
+ height: 100px;
48
+ resize: none;
49
+ }
50
+
51
+ input[type="submit"] {
52
+ margin-top: 10px;
53
+ padding: 10px 20px;
54
+ background-color: #0ff;
55
+ border: none;
56
+ border-radius: 5px;
57
+ cursor: pointer;
58
+ transition: background-color 0.3s;
59
+ }
60
+
61
+ input[type="submit"]:hover {
62
+ background-color: #08e;
63
+ }
64
+
65
+ h2 {
66
+ color: white;
67
+ margin-top: 30px;
68
+ border-top: 2px solid #0ff;
69
+ padding-top: 10px;
70
+ }
71
+
72
+ .result {
73
+ margin-top: 20px;
74
+ color: #0ff;
75
+ }
76
+ .safe {
77
+ color: rgb(0, 255, 0);
78
+ }
79
+
80
+ .phishing {
81
+ color: red;
82
+ }
83
+ </style>
84
+ </head>
85
+ <body>
86
+ <h1>Web Phishing Detection</h1>
87
+ <form action="/" method="post">
88
+ <h2>Check if a URL is Safe or Phishing</h2>
89
+ <input type="text" id="url" name="url" placeholder="Enter URL" required>
90
+ <input type="submit" value="Check URL">
91
+ </form>
92
+
93
+ {% if result %}
94
+ <div class="result">
95
+ <div class="result {{ result_class }}">
96
+ <h2>URL Check Result</h2>
97
+ <h1><p>{{ result }}</p></h1>
98
+ <h3><p>URL: {{ url }}</p></h3>
99
+ </div>
100
+ {% endif %}
101
+ </body>
102
+ </html>