自己最近也刚开始学习网站安全的技术,以下有写的不对的地方还请高手多指点啊.
网站漏洞主要集中在动态网页中,静态网站基本不存在什么漏洞。
1.sql注入和跨站点脚本攻击
2.上传漏洞
3.文本编辑器漏洞
4.网站目录及密码安全
解决办法:
1.sql注入和跨站点脚本攻击:对这类漏洞来说就是用一些安全扫描工具进行检测,然后修复,以下是我个人总结的一点小知识:
对于asp网站:
一。跨站点攻击
1.在需要用户或管理员输入数据的地方用js去除危险字符
js脚本:
function RemoveBad(strTemp) {
strTemp = strTemp.replace(/[$ <> & % ' ( ) + - = " ; / ]/g, "")
return strTemp;
}
//asp脚本方法
<%
'过滤掉危险的html和特殊字符,防止跨网站攻击
function nohtml(str)
dim re
Set re=new RegExp
re.IgnoreCase =true
re.Global=True
re.Pattern="(/<.[^/<]*/>)"
str=re.replace(str," ")
re.Pattern="(/<//[^/<]*/>)"
str=re.replace(str,"")
re.Pattern="([/'/&/-/+/=/(/)/;/[/]/{/}])" '去除特殊符号
str=re.replace(str,"")
nohtml=str
set re=nothing
end function
'对要显示的数据进行编码,防止显示危险字符
function showdata(str)
showdata=server.HTMLEncode(nohtml(str))
end function
%>
对于aspx网站来说,有一个通用的安全检测类是很重要的,以下是个人总结:
namespace DZ.Security
{
//输入数据安全性相关
public class Sec
{
#region 检测输入的内容是否有攻击的可能性
/// <summary>
/// 检测输入的内容是否有攻击的可能性
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string par_queryString_forStr(string str)
{
//大于20很可能是注入攻击
string str_process = null;
if (str.Length > 20)
{
str_process = str.Substring(0, 20);
}
else
{
str_process = str;
}
return str_process;
}
#endregion
#region 检测int 类型的id号的和法性
/// <summary>
/// 检测int 类型的id号的和法性
/// </summary>
/// <param name="str">要检测的字符</param>
/// <returns></returns>
public static string par_queryString_forId(string str)
{
//ID数字 整型 最大值65535 不超过5个数字
string str_process = null;
if (str.Length > 5)
{
str_process = str.Substring(0, 5);
}
else
{
str_process = str;
}
return str_process;
}
#endregion
#region 硬性过滤脏字符串
/// <summary>
/// 硬性过滤脏字符串
/// </summary>
/// <param name="str">要处理的字符串</param>
/// <returns></returns>
public static string par_filter_forNews(string str)
{
//硬性过滤
//依次为 **竞争对手,拿我的免费产品卖钱的家伙
string[] filterStr = {
**
//领风五年,域名:
};
int filterLen = filterStr.Length;
for (int i = 0; i < filterLen; i++)
{
str = str.Replace(filterStr[i], "");
}
return str;
}
#endregion
#region 对危险的html,Sql标记和特殊符号进行过滤
/// <summary>
/// 对危险的html,Sql标记和特殊符号进行过滤
/// </summary>
/// <param name="strHtml">要过滤的字符串</param>
/// <returns>过滤后的字符串</returns>
public static string FilterToTxt(string strHtml)
{
string[] aryReg = {
@"<script[^>]*?>.*?</script>",
@"<(///s*)?!?((/w+:)?/w+)(/w+(/s*=?/s*(([""'])(//[""'tbnr]|[^/7])*?/7|/w+)|.{0})|/s)*?(///s*)?>",
@"([/r/n])[/s]+",
@"&(quot|#34);",
@"&(amp|#38);",
@"&(lt|#60);",
@"&(gt|#62);",
@"&(nbsp|#160);",
@"&(iexcl|#161);",
@"&(cent|#162);",
@"&(pound|#163);",
@"&(copy|#169);",
@"&#(/d+);",
@"-->",
@"<!--.*/n",
@"select",
@"delete",
@"update",
@"insert into",
@"Insert",
@"Delete",
@"update",
@"create",
@"drop",
@"exec",
@"dri",
@"[^/w/[email protected]]"
};
string strOutput = strHtml;
for (int i = 0; i < aryReg.Length; i++)
{
Regex regex = new Regex(aryReg[i], RegexOptions.IgnoreCase);
strOutput = regex.Replace(strOutput, string.Empty);
}
return strOutput;
}
#endregion
}
//数据加密,解密
public class EncAndDec
{
public string _QueryStringKey = "logowang"; //URL传输参数加密Key abcdefgh
public string _PassWordKey = "hgfedcba"; //PassWord加密Key
#region url 参数加密解密
public static string UrlDecode(string input)
{
return HttpUtility.UrlDecode(input);
}
public static string UrlEncode(string input)
{
return HttpUtility.UrlEncode(input);
}
#endregion
#region md5字符串加密
/// <summary>
/// md5字符串加密
/// </summary>
/// <param name="str">要加密字符串</param>
/// <returns></returns>
public string MD5Encrypt(string str)
{
try
{
byte[] hashvalue = (new MD5CryptoServiceProvider()).ComputeHash(Encoding.UTF8.GetBytes(str));
return BitConverter.ToString(hashvalue);
}
catch
{
return String.Empty;
}
}
#endregion
#region 加密解密相关
/// <summary>
/// 加密URL传输的字符串
/// </summary>
/// <param name="QueryString">要加密的字符串</param>
/// <returns></returns>
public string EncryptQueryString(string QueryString)
{
return Encrypt(QueryString, _QueryStringKey);
}
/// <summary>
/// 解密URL传输的字符串
/// </summary>
/// <param name="QueryString">要解密的字符串</param>
/// <returns></returns>
public string DecryptQueryString(string QueryString)
{
return Decrypt(QueryString, _QueryStringKey);
}
///
/// 加密帐号口令
///
///
///
public string EncryptPassWord(string PassWord)
{
return Encrypt(PassWord, _PassWordKey);
}
/// <summary>
/// 解密帐号口令
/// </summary>
/// <param name="PassWord"></param>
/// <returns></returns>
public string DecryptPassWord(string PassWord)
{
return Decrypt(PassWord, _PassWordKey);
}
/// <summary>
/// DEC 加密过程
/// </summary>
/// <param name="pToEncrypt">要加密的字符串</param>
/// <param name="sKey">加密密钥</param>
/// <returns></returns>
public string Encrypt(string pToEncrypt, string sKey)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider(); //把字符串放到byte数组中
byte[] inputByteArray = Encoding.Default.GetBytes(pToEncrypt);
//byte[] inputByteArray=Encoding.Unicode.GetBytes(pToEncrypt);
des.Key = ASCIIEncoding.ASCII.GetBytes(sKey); //建立加密对象的密钥和偏移量
des.IV = ASCIIEncoding.ASCII.GetBytes(sKey); //原文使用ASCIIEncoding.ASCII方法的GetBytes方法
System.IO.MemoryStream ms = new System.IO.MemoryStream(); //使得输入密码必须输入英文文本
CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
StringBuilder ret = new StringBuilder();
foreach (byte b in ms.ToArray())
{
ret.AppendFormat("{0:X2}", b);
}
ret.ToString();
return ret.ToString();
}
/// <summary>
/// DEC 解密过程
/// </summary>
/// <param name="pToDecrypt">要解密的字符串</param>
/// <param name="sKey">解密密钥</param>
/// <returns></returns>
public string Decrypt(string pToDecrypt, string sKey)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
for (int x = 0; x < pToDecrypt.Length / 2; x++)
{
int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
inputByteArray[x] = (byte)i;
}
des.Key = ASCIIEncoding.ASCII.GetBytes(sKey); //建立加密对象的密钥和偏移量,此值重要,不能修改
des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();
StringBuilder ret = new StringBuilder(); //建立StringBuild对象,CreateDecrypt使用的是流对象,必须把解密后的文本变成流对象
return System.Text.Encoding.Default.GetString(ms.ToArray());
}
/// <summary>
/// 检查己加密的字符串是否与原文相同
/// </summary>
/// <param name="EnString">加密的url</param>
/// <param name="FoString">加密的Password</param>
/// <param name="Mode">1:检测url参数,2:检测Password</param>
/// <returns></returns>
public bool ValidateString(string EnString, string FoString, int Mode)
{
switch (Mode)
{
default:
case 1:
if (Decrypt(EnString, _QueryStringKey) == FoString.ToString())
{
return true;
}
else
{
return false;
}
case 2:
if (Decrypt(EnString, _PassWordKey) == FoString.ToString())
{
return true;
}
else
{
return false;
}
}
}
#endregion
}
}
2.在需要显示数据的地方用Html.encode()方法进行编码,如下:
在执行页中我们加入:
strUserName =server.HTMLEncode(Request.QueryString("userName"))
和
strUserName =server.HTMLEncode(Request.Form("userName"))
二。sql输入攻击
主要是在数据查询页面,对传过来的参数进行安全检测,避免不符合要求的参数进行数据库查询。如下:
if(Not IsNumeric(id)) then
Response.write("没有相关数据")
else
进行数据查询并显示数据
end if
2.上传漏洞:主要是对用户上传的文件进行检测,这个特别是在编写程序时特别重要,以下是我用到的aspx。上传检测代码:
#region 实现图片上传lblhasPic,FileUpload1 lbladdArtic
protected void upLoadPic(Label lblp, Label lblisSuccess, FileUpload fileload)
{
lblisSuccess.Text = "";
lblp.ForeColor = System.Drawing.Color.Red;
if (fileload.HasFile)
{
string fileContentType = fileload.PostedFile.ContentType;
#region 获取上传文件的文件名并判断文件的合法性
bool fileOk = true;
string name = fileload.PostedFile.FileName; // 客户端文件路径
FileInfo file = new FileInfo(name);
string fileName = file.Name; // 文件名称
if (fileName.Contains(";"))//上传文件含有分号,很有能是上传图片木马的前兆
{
fileOk = false;
}
#endregion
if (fileOk)
{
if (fileContentType == "image/bmp" || fileContentType == "image/gif" || fileContentType ==
"image/pjpeg")
{
int isHasPic;//视频图片是否存在
string relImgPath = "/hqvideo/advancedusers/VideoPictures/" + Session["username"].ToString() + "/" + Request.QueryString["ID"].ToString() + "/";
String path = Server.MapPath(relImgPath);//保存上传文件的文件夹upload虚拟路径对应的实际路径
string pt = path;
// picFileName = fileName;
if (!Directory.Exists(pt)) //如果文件夹不存在则创建
{
Directory.CreateDirectory(pt);
}
string webFilePath = pt + fileName; // 服务器端文件路径
//向数据库中添加视频信息
isHasPic = addVideoPic(fileName, relImgPath + fileName, txbpicinfo.Text, 0);
if (isHasPic != -1)
{
try
{
fileload.SaveAs(webFilePath); // 使用 SaveAs 方法保存文件
//最后一部高级验证,图片上传后的操作,判断是否真的是图片
StreamReader sr = new StreamReader(webFilePath, Encoding.Default);
string img = "";
string strContent = sr.ReadToEnd();
sr.Close();
string str = "request|script|.getfolder|.createfolder|.deletefolder|.createdirectory|.deletedirectory|.saveas|wscript.shell|script.encode|server.|.createobject|execute|activexobject|language=|public|dim";
foreach (string s in str.Split('|'))
if (strContent.IndexOf(s) != -1)
{
File.Delete(webFilePath);
img = "No";
break;
}
//删除源文件
if (img == "No" && File.Exists(webFilePath))
{
File.Delete(webFilePath);//如果文件已经存在就删除
lblp.ForeColor = System.Drawing.Color.Red;
lblp.Text = "提示:文件格式不正确";
}
else
{
lblp.ForeColor = System.Drawing.Color.Green;
lblp.Text = "提示:文件“" + fileName + "”成功上传";
}
txbpicinfo.Text = "";
}
catch (Exception ex)
{
lblp.Text = "提示:文件上传失败,失败原因:" + ex.Message;
}
}
else
{
lblp.Text = "提示:文件已经存在,请重命名后上传";
}
}
else
{
lblp.Text = "提示:文件类型不符";
}
}
else
{
lblp.Text = "请先选择要上传的图片";
}
}
else
{
lblp.Text = "提示:文件类型不符";
}
}
#endregion
3.对文本编辑器漏洞来说主要的还是上传漏洞,如果再自己的项目中没有用到上传的功能还是把上传功能关闭,对新下载的文本编辑器,删除里面的实例程序一般都会以_开头,最好对文本编辑器所在的目录进行用户身份的验证。
4.
网站目录不要采取带有明显管理员信息的目录,如:admin,manager,等。采取自定义的命名方式。。可有效提高安全性,黑客在想进入你的后台时要先找到登陆地址,如果用上述的目录来说,就少了一份安全性,还有的网站为了方便管理,干脆把后台登陆地址放到了前台页面上,这样不是给黑客提供了方便吗?
有些网站后台密码太简单,这种问题很多是在一些企业网站里,由于企业用户缺乏安全知识,往往密码很简单,增加网站密码的安全性也是很重要的。