├── README.md ├── url_svm.py ├── html_svm.py └── README.html /README.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | #基于启发式特征的钓鱼网站检测系统 3 | #__Author__:沂水寒城 4 | 5 | ##背景 6 | 钓鱼网站的检测问题可以看做是一个二分类的问题,因此可以基于机器学习的流程和方法来做分类 7 | 8 | ##基于html的启发式钓鱼网站检测 9 | 基于数据的大量统计以及综合已有的方法提取29维特征,之后使用SVM模型来训练和测试 10 | 11 | ##基于url的启发式钓鱼网站检测 12 | 基于url的特征设计的轻量级的分类模型,同样是基于SVM分类模型 13 | 14 | ##实验方案 15 | 实验采用的方法是结合两个分类模型的结果综合决策最终页面的所属类别 16 | 17 | ##实验数据 18 | 由于爬取得到的html文件较大不易上传就不提供数据了 ,url的数据可以在我的malicious_web_page_detection_based_on_url里面找到,数据是可以通用的,在malicious_web_page_detection_based_on_url里面着重是使用sklearn中的机器学习模型来测试,而这个工作主要是集中在特征工程方面,这样合在一起就是一个完整的机器学习实践的流程了。 -------------------------------------------------------------------------------- /url_svm.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/python 2 | #-*-coding:utf-8-*- 3 | 4 | 5 | ''' 6 | __Author__:沂水寒城 7 | 功能:基于url的特征设计轻量级的仿冒网站检测工具 8 | ''' 9 | 10 | 11 | import codecs 12 | import sys 13 | import re 14 | from urllib2 import urlparse 15 | 16 | 17 | 18 | RED_KEYWORDS = ["account", "admin", "administrator", 19 | "auth", "bank", "client", "confirm", "email", "host", 20 | "password", "pay", "private", "safe", "secure", "security", 21 | "sign", "user", "validation", "verification", "icbc"] 22 | PATH_KEYWORDS = ["www", "net", "com", "cn"] 23 | 24 | 25 | 26 | def geturlat(url): 27 | ''' 28 | 判断URL中是否含有@,?,-,_等符号 29 | ''' 30 | re_script = re.compile(r'@|-|_|\?|~') 31 | return 1 if re_script.search(url) else 0 32 | 33 | def get_has_ip(url): 34 | ''' 35 | 判断url中是否包含ip,包含返回1,不包含返回0 36 | ''' 37 | compile_rule_ip = re.compile(r'(?(.*?)", Html) 28 | if len(match) > 13: 29 | return 1 30 | else: 31 | return 0 32 | 33 | 34 | def get_embed_num(Html): 35 | ''' 36 | 获得HTML中的标签数量(特征大多为0) 37 | ''' 38 | match = re.compile(r']+/>|]+[^/>]>') 39 | embed_list = re.findall(match, Html) 40 | return len(embed_list) 41 | 42 | 43 | def get_iframe_num(Html): 44 | ''' 45 | 获得html中的') 48 | iframe_list = re.findall(match, Html) 49 | return len(iframe_list) 50 | 51 | 52 | def get_applet_num(Html): 53 | ''' 54 | 获得html中的标签的数量(特征大多为0) 55 | ''' 56 | match = re.compile(r'') 57 | applet_list = re.findall(match, Html) 58 | return len(applet_list) 59 | 60 | 61 | def get_frame_num(Html): 62 | ''' 63 | 获得html中的标签的数量(特征大多为0) 64 | ''' 65 | match = re.compile(r']+/>|]+[^/>]>') 66 | frame_list = re.findall(match, Html) 67 | return len(frame_list) 68 | 69 | 70 | def get_form_get_num(Html): 71 | ''' 72 | 提取form中的get方法数量(特征大多为0) 73 | ''' 74 | match = re.compile(r'') 75 | get_list = re.findall(match, Html) 76 | return len(get_list) 77 | 78 | 79 | def get_form_post_num(Html): 80 | ''' 81 | 提取form中的post方法数量(特征大多为0和1) 82 | ''' 83 | match = re.compile(r'') 84 | post_list = re.findall(match, Html) 85 | if len(post_list) > 1: 86 | return 1 87 | else: 88 | return 0 89 | 90 | 91 | def get_js_long(Html): 92 | ''' 93 | 计算网页中的script内容长度(特征大多为0) 94 | ''' 95 | script_num = 0 96 | # 抽取script包含的内容 97 | re_alert = re.compile(r">\s*alert[\S\s]*") 98 | alert_content = re_alert.findall(Html) 99 | # 计算script中内容的字符长度 100 | if alert_content != []: 101 | for once_alert_content in alert_content: 102 | script_num += len(once_alert_content) 103 | if script_num > 0: 104 | return 1 105 | else: 106 | return 0 107 | 108 | 109 | def get_divonClick_num(Html): 110 | ''' 111 | 计算html中
方法出现的数量(均为0) 112 | ''' 113 | match = re.compile(r'<body>的数量 121 | ''' 122 | #match = re.compile(r'<head>[\s\S]*<title>[\s\S]*<body>[\s\S]*</head>') 123 | head_num = 0 124 | title_num = 0 125 | body_num = 0 126 | match_head = re.compile(r'<head>[\s\S]*</head>') 127 | match_title = re.compile(r'<title>[\s\S]*') 128 | match_body = re.compile(r'') 129 | head_list = re.findall(match_head, Html) 130 | title_list = re.findall(match_title, Html) 131 | body_list = re.findall(match_body, Html) 132 | for head_content in head_list: 133 | head_num += head_content.count('') 134 | for body_content in body_list: 135 | body_num += body_content.count('') 138 | if head_num > 0: # 1或者2 139 | head_num = 1 140 | else: 141 | head_num = 0 142 | if body_num > 0: # 1或者2 143 | body_num = 1 144 | else: 145 | body_num = 0 146 | if title_num > 0: # 1或者2 147 | title_num = 1 148 | else: 149 | title_num = 0 150 | return [head_num, title_num, body_num] 151 | #return head_list, title_list, body_list 152 | # print len(head_list), len(title_list), len(body_list) 153 | # print head_num, title_num, body_num 154 | 155 | 156 | def get_input_num(Html): 157 | ''' 158 | 计算html中的标签数量 159 | ''' 160 | #match = re.compile(r'') 161 | input_num = 0 162 | match = re.compile(r' 5: 167 | return 1 168 | else: 169 | return 0 170 | 171 | 172 | def get_form_num(Html): 173 | ''' 174 | 计算html中的
表单数量 175 | ''' 176 | form_num = 0 177 | match = re.compile(r'') 178 | form_list = re.findall(match, Html) 179 | # print 'form_list is :', form_list 180 | # print 'len_form_list is :', len(form_list) 181 | for form_content in form_list: 182 | form_num += form_content.count('') 183 | #form = form_list[0] 184 | #form_num_list = form.split('') 185 | #form_num = len(form_num_list) - 1 186 | # print form_num 187 | if form_num > 0:#以1,2,3居多,有较大值 188 | return 1 189 | else: 190 | return 0 191 | 192 | 193 | def get_SetIntervel_num(html): 194 | ''' 195 | 获取页面html中SetIntervel()方法数量 196 | ''' 197 | match = re.compile(r'setInterval\([\s\S]*\)', re.I) 198 | setInterval_list = re.findall(match, html) 199 | if len(setInterval_list)>0:#多数为0.有极少数为1 200 | return 1 201 | else: 202 | return 0 203 | 204 | 205 | def get_SetTimeout_num(html): 206 | ''' 207 | 获取页面html中SetTimeout()方法数量 208 | ''' 209 | match = re.compile(r'setTimeout\([\s\S]*\)', re.I) 210 | setTimeout_list = re.findall(match, html) 211 | if len(setTimeout_list) > 0:#多数为0.有少数为1 212 | return 1 213 | else: 214 | return 0 215 | 216 | 217 | def get_onload_num(html): 218 | ''' 219 | 获取页面html中onload()方法数 220 | ''' 221 | match = re.compile(r'onload\([\s\S]\)', re.I) 222 | onload_list = re.findall(match, html) 223 | if len(onload_list)>0:#多数为0.微量为1 224 | return 1 225 | else: 226 | return 0 227 | 228 | 229 | def get_onerror_num(html): 230 | ''' 231 | 获取页面html中onerror()方法数 #测试均为0 232 | ''' 233 | match = re.compile(r'onerror\([\s\S]*\)', re.I) 234 | onerror_list = re.findall(match, html) 235 | return len(onerror_list) 236 | 237 | 238 | def get_js_functions_num(html): 239 | ''' 240 | 获取页面html中js调用的方法数 241 | ''' 242 | match_script = re.compile(r'') 243 | script_list = re.findall(match_script, html) 244 | '''代码报错,数组越界 245 | script = script_list[0] 246 | ''' 247 | match_functions = re.compile(r'function') 248 | functions_list = re.findall(match_functions, script) 249 | return len(functions_list) 250 | 251 | 252 | def get_script_functions_num(html): 253 | ''' 254 | 获取页面html中') 257 | script_list = re.findall(match_script, html) 258 | '''代码报错,数组越界 259 | script = script_list[0] 260 | ''' 261 | match_functions = re.compile(r'function') 262 | functions_list = re.findall(match_functions, script) 263 | return len(functions_list) 264 | 265 | 266 | def get_pop_num(html): 267 | ''' 268 | 获取页面html中pop()方法数 269 | ''' 270 | match = re.compile(r'pop\([\s\S]*\)', re.I) 271 | pop_list = re.findall(match, html) 272 | if len(pop_list) >0: 273 | return 1 274 | else: 275 | return 0 276 | 277 | 278 | def get_exec_num(html): 279 | ''' 280 | 获取页面html中的exec()方法数 281 | ''' 282 | match = re.compile(r'exec\([\s\S]*\)', re.I) 283 | exec_list = re.findall(match, html) 284 | if len(exec_list) > 0: 285 | return 1 286 | else: 287 | return 0 288 | 289 | 290 | def get_Dispatchevent_num(html): 291 | ''' 292 | 获取页面html中DispatchEvent()方法数 293 | ''' 294 | match = re.compile(r'dispatchevent\([\s\S]*\)', re.I) 295 | dispatchevent_list = re.findall(match, html) 296 | return len(dispatchevent_list) 297 | # 极少数为0 298 | 299 | 300 | def get_Eval_num(html): 301 | ''' 302 | 获取页面html中Eval()方法数 303 | ''' 304 | match = re.compile(r'Eval\([\s\S]*\)', re.I) 305 | eval_list = re.findall(match, html) 306 | if len(eval_list) > 0: 307 | return 1 308 | else: 309 | return 0 310 | 311 | 312 | def get_attachevent_num(html): 313 | ''' 314 | 获取页面html中attachEvent()方法数 315 | ''' 316 | match = re.compile(r'attachevent\([\s\S]*\)', re.I) 317 | attachevent_list = re.findall(match, html) 318 | if len(attachevent_list) > 0: 319 | return 1 320 | else: 321 | return 0 322 | 323 | 324 | def get_formcharcode_num(html): 325 | ''' 326 | 获取页面html中formcharcode()方法数 327 | ''' 328 | match = re.compile(r'formcharcode\([\s\S]*\)', re.I) 329 | formcharcode_list = re.findall(match, html) 330 | return len(formcharcode_list) 331 | #测试文件均为0 332 | 333 | 334 | def extract_html_feature(html_path): 335 | ''' 336 | 读取html文件,并抽取title分词后名词、正文关键词、ICP号, 均为字符串格式, 337 | 关键词由'/'分隔 338 | ''' 339 | html = utf8_open_file(html_path) 340 | title_keyword = get_title_cut(html) 341 | text_keyword = get_html_keyword(html) 342 | ICP = get_ICP(html) # 抽取html中ICP 343 | return title_keyword, text_keyword, ICP 344 | #这个函数有两个函数没有 345 | 346 | 347 | def get_html_vector(Html): 348 | heuristic_vector = [] 349 | soup = BeautifulSoup(Html, "lxml") 350 | if soup != None: 351 | heuristic_vector.append(get_html_length(Html)) 352 | heuristic_vector.append(get_div_num(Html)) 353 | heuristic_vector.append(get_embed_num(Html)) 354 | heuristic_vector.append(get_iframe_num(Html)) 355 | heuristic_vector.append(get_applet_num(Html)) 356 | heuristic_vector.append(get_frame_num(Html)) 357 | heuristic_vector.append(get_form_get_num(Html)) 358 | heuristic_vector.append(get_form_post_num(Html)) 359 | heuristic_vector.append(get_js_long(Html)) 360 | heuristic_vector.append(get_divonClick_num(Html)) 361 | heuristic_vector.extend(get_headtitlebody_num(Html)) 362 | heuristic_vector.append(get_input_num(Html)) 363 | heuristic_vector.append(get_form_num(Html)) 364 | heuristic_vector.append(get_SetIntervel_num(Html)) 365 | heuristic_vector.append(get_SetTimeout_num(Html)) 366 | heuristic_vector.append(get_onload_num(Html)) 367 | heuristic_vector.append(get_onerror_num(Html)) 368 | heuristic_vector.append(get_form_get_num(Html)) 369 | heuristic_vector.append(get_form_post_num(Html)) 370 | heuristic_vector.append(get_pop_num(Html)) 371 | heuristic_vector.append(get_exec_num(Html)) 372 | heuristic_vector.append(get_Dispatchevent_num(Html)) 373 | heuristic_vector.append(get_Eval_num(Html)) 374 | heuristic_vector.append(get_attachevent_num(Html)) 375 | heuristic_vector.append(get_formcharcode_num(Html)) 376 | heuristic_vector.append(get_form_get_num(Html)) 377 | heuristic_vector.append(get_form_post_num(Html)) 378 | return heuristic_vector 379 | 380 | if __name__ == '__main__': 381 | html_baidu = urllib2.urlopen('http://www.baidu.com').read() 382 | baidu_vector = [] 383 | baidu_vector = get_html_vector(html_baidu) 384 | print baidu_vector 385 | ''' 386 | [111666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0] 387 | ''' 388 | -------------------------------------------------------------------------------- /README.html: -------------------------------------------------------------------------------- 1 | README
1030 |

基于启发式特征的钓鱼网站检测系统

1031 |

Author:沂水寒城

1032 |

背景

1033 |

钓鱼网站的检测问题可以看做是一个二分类的问题,因此可以基于机器学习的流程和方法来做分类

1034 |

基于html的启发式钓鱼网站检测

1035 |

基于数据的大量统计以及综合已有的方法提取29维特征,之后使用SVM模型来训练和测试

1036 |

基于url的启发式钓鱼网站检测

1037 |

基于url的特征设计的轻量级的分类模型,同样是基于SVM分类模型

1038 |

实验方案

1039 |

实验采用的方法是结合两个分类模型的结果综合决策最终页面的所属类别

1040 |

实验数据

1041 |

由于爬取得到的html文件较大不易上传就不提供数据了 ,url的数据可以在我的malicious_web_page_detection_based_on_url里面找到,数据是可以通用的,在malicious_web_page_detection_based_on_url里面着重是使用sklearn中的机器学习模型来测试,而这个工作主要是集中在特征工程方面,这样合在一起就是一个完整的机器学习实践的流程了。

--------------------------------------------------------------------------------