在C#中编写多线程应用程序
以前在使用VB来实现多线程的时候,发现有一定的难度。虽然也有这样那样的方法,但都不尽人意,但在C#中,要编写多线程应用程序却相当的简单。这篇文章将作简要的介绍,以起到抛砖引玉的作用! .NET将关于多线程的功能定义在System.Threading名字空间中。因此,要使用多线程,必须先声明引用此名字空间(using System.Threading;)。 即使你没有编写多线程应用程序的经验,也可能听说过“启动线程”“杀死线程”这些词,其实除了这两个外,涉及多线程方面的还有诸如“暂停线程”“优先级”“挂起线程”“恢复线程”等等。下面将一个一个的解释。 1.启动线程 顾名思义,“启动线程”就是新建并启动一个线程的意思,如下代码可实现: Thread thread1 = new Thread(new ThreadStart( Count)); 其中的 Count 是将要被新线程执行的函数。 2.杀死线程 “杀死线程”就是将一线程斩草除根,为了不白费力气,在杀死一个线程前最好先判断它是否还活着(通过 IsAlive 属性),然后就可以调用 Abort 方法来杀死此线程。 3.暂停线程 它的意思就是让一个正在运行的线程休眠一段时间。如 thread.Sleep(1000); 就是让线程休眠1秒钟。 4.优先级 这个用不着解释了。Thread类中有一个ThreadPriority属性,它用来设置优先级,但不能保证操作系统会接受该优先级。一个线程的优先级可分为5种:Normal, AboveNormal, BelowNormal, Highest, Lowest。具体实现例子如下: thread.Priority = ThreadPriority.Highest; 5.挂起线程 Thread类的Suspend方法用来挂起线程,直到调用Resume,此线程才可以继续执行。如果线程已经挂起,那就不会起作用。 if (thread.ThreadState = ThreadState.Running) { thread.Suspend(); } 6.恢复线程 用来恢复已经挂起的线程,以让它继续执行,如果线程没挂起,也不会起作用。 if (thread.ThreadState = ThreadState.Suspended) { thread.Resume(); } 下面将列出一个例子,以说明简单的线程处理功能。此例子来自于帮助文档。 using System; using System.Threading; // Simple threading scenario: Start a static method running // on a second thread. public class ThreadExample { // The ThreadProc method is called when the thread starts. // It […]
View Details线程间操作无效: 从不是创建控件 [控件名称] 的线程访问它
我现在正在使用vs2010英文版,平常也很少看那些有的没的文字,而且在写程序的时候很”明智”的异常捕获并且写进日志里去,所以没有出现那个可爱的调试状态下出现异常的那个小框框. 我在上网查了一会儿,有人说直接设置控件的CheckForIllegalCrossThreadCalls属性为false,但是因为可能的不安全因素所以还是不用的好.当然还有写一个委托来同步调用.但是我觉得它有点麻烦,就放弃用委托同步了. 后来我搞了好多种写法,都摆脱不了这个怨念,最终也摆脱了异常捕获并抛出了这个小框框. 框框上明确的说道:”线程间操作无效: 从不是创建控件 [控件名称] 的线程访问它。”但是在框框的Suggestion列表中显示出了一条项目,大意是:”如何:对 Windows 窗体控件进行线程安全调用.”,我点开它,并且跳进了MSDN. 原来在MSDN上就有教咱如果夸线程操作控件啊.亏我还Google半天呢. MSDN上的办法就是使用委托来同步调用控件的.具体方法我也就不卖关子了.因为MSDN上的代码比较繁多,所以我稍微改进了一下. //首先声明一个委托. delegate void SetValueDelegate(int val); //模仿程序中的跨线程调用 public void Progress() { Thread t = new Thread(() => { //跨线程由此开始 SetValue(100); }); t.Start(); } //关键部分在这里 public void SetValue(int val) { //InvokeRequired属性当非创建本控件线程操作的时候 //它返回true,此时使用窗体(该控件的创建者)的Invoke方法创建同步调用. //妙哉,妙哉! if (ProgressBar1.InvokeRequired) { var svd = new SetValueDelegate(SetValue); this.Invoke(svd, val); } else { ProgressBar1.Value = val; } } 好了,就是这样,非讨论文章就越精炼越好.希望能帮到你. 最后附上MSDN的地址:这里
View Detailswindow.event.keyCode兼容Firefox
1.window.event.keyCode的用法: 例子、<input type="text" onkeydown="javaScript:if(window.event.keyCode==13) kenNumIE();" /> <script language="javascript" type="text/javascript"> function kenNumIE(){ alert("你按的是回车键!"); } </script> 但是该方法只对IE有效,原因是Firefox的window对象没有event属性,所以window.event是不存在的,Firefox只能在事件句柄函数的第一个参数获取事件对象。2.兼容Firefox的方法:<input type="text" onkeydown="return keyNumAll(event);" > <script language="javascript" type="text/javascript"> function keyNumAll(evt){ var k=window.event?evt.keyCode:evt.which; if(k == 13){ alert("你按的是回车键!"); } } </script> 这样,当你按回车键时,就可以触发keyNumAll(event)事件了。 附:window.event.keyCode 集合(键盘字符的Ascii): XML/HTML代码 Ascii 代码表 Ascii 0 {Nulo, Sem Som} Ascii 1 Ascii 2 Ascii 3 Ascii 4 Ascii 5 Ascii 6 Ascii 7 Ascii 8 {BackSpace} Ascii 9 {Tab} Ascii 10 Ascii 11 Ascii 12 Ascii 13 {Enter} Ascii 14 Ascii 15 Ascii 16 {Shift} Ascii 17 {CTRL} Ascii 18 {ALT} Ascii 19 Ascii 20 {CapsLock} Ascii 21 Ascii 22 Ascii 23 Ascii 24 Ascii 25 Ascii 26 Ascii 27 Ascii 28 Ascii 29 – Ascii 30 – Ascii 31 Ascii 32 {Espa?o} ! Ascii 33 " Ascii 34 # Ascii 35 $ Ascii 36 % Ascii 37 & Ascii 38 ' Ascii 39 ( Ascii 40 ) Ascii 41 * Ascii 42 + Ascii 43 , Ascii 44 – Ascii 45 . Ascii 46 / Ascii 47 0 Ascii 48 1 Ascii 49 […]
View Details中国的现状
我转发此文并不是想破坏和谐,我只是想让祖国越来越好,希望那些应该看到此文的人看到。在一个国家发展的历程中不能总是只看到鲜花和掌声吧? 李一帆案判决结果:李一帆因交通肇事罪判有期徒刑三年,监外执行。赔偿被害人家属三十万伤者五万。李一帆被实习单位开除,李刚被调往其它分局做副局长。张晶晶已经给河北大学及保定公安局北市区分局软禁在医院,禁止媒体记者采访。同时河北大学已经将死者和伤者的同一宿舍室友女生(现大一)全部保研。转发你所有的群,让人都看看天理何在!!! 上海静安大火快速抓捕8名无证电焊工再一次验证了韩寒所说的,“中国现阶段的主要矛盾是人民群众日益增长的智商和官员们不断下降的道德之间的矛盾。” 农民工干着最苦最累的活,拿着最低的工资,在官员眼里又多了一项功能“替罪羊”。 电焊工,农民工,临时工,挣的是卖白菜的钱,顶的是卖白粉的罪。 上海当局用了250个场馆、6个月的时间、7300万人来宣扬“城市让生活更美好”,而1幢大楼、4个小时、53位亡灵证明了这不过是一个口号。 一个国家的文明程度,不在于能不能办奥运会,不在于能不能办世博会,能不能办亚运会,也不在于能买多少美国垃圾国债,更不在于能去国外几十亿几百亿下订单,而是在于让公民坐在家里不会被烧死、上街摆摊不会被扇耳光,走路不会被李刚家的宝马车撞,想吃什么都不用担心会有毒。 这个世界就是:不吸烟的得肺癌,不工作的做老板,不爱国的当大官;真正的爱不能要,真正的事不能干,真正的人不能做;需要书的读不起,需要房的买不起,需要人的娶不起;有文化的留不了学,有能力的找不到活,有良知的赚不了钱。 三聚氰胺害了那么多儿童,最后抓了几个养奶牛的;央视大火烧掉10几亿,抓了几个运烟火的;上海静安大火烧死53人,是4个电焊工的责任!跟西游记一样,有背景的妖怪都被带走了,没背景的妖怪都被乱棍打死 豹子办了个澡堂子,包给狐狸,狐狸包给松鼠,松鼠雇几只蚂蚁搓澡接客。有一天,狮子去洗澡,掉脸盆里淹死了。。。。虎大王震怒,派警察调查情况,骂了狐狸,打了松鼠,最后,抓了8只蚂蚁。。。。因为他们,竟然没搓澡证! 最近,国家某部公布了一项统计数据,告诉人们:你要不是三大式人物(大款,大官,大腕)而想在北京买套100平方米总价300万的房,社会阶层所付出的代价请看:1 农民:种三亩地每亩纯收入400元的话要从唐朝开始至今才能凑齐(还不能有灾年);2 工人:每月工资1500元需从鸦片战争上班至今(双休日不能休);3 白领:年薪6万,需从1960年上班就拿这么多钱至今不吃不喝(取消法定假日);4 抢劫犯:连续作案2500次(必须事主是白领)约30年。5:妓女:连续接客10000次,以每天都接一次客,需备战10000天,从18岁起按此频率接客到46岁(中间还不能来例假)以上还不算装修、家具、家电等等费用中国的现状(经典) 1、ATM取出假钱—>银行无责 2、网上银行被盗—>储户责任 3、银行多给了钱—>储户义务归还 4、银行少给了钱—>离开柜台概不负责 5、ATM机出现故障少给钱—>用户负责 6、ATM机出现故障多给钱—>用户盗窃 7、广东开平银行行长贪污4亿—>判2年 8、ATM多吐7万给老百姓许霆—>判无期 声明:转发不会送人民币,但如果觉得作为消费者,全中国十三亿储户不公平的,请转发 ,有多少群转发多少群 中国现状: 生不起,剖腹一刀五千起; 读不起,选个学校三万起; 住不起,二万多元一平米; 老婆不是娶不起,没房没车谁嫁你? 养不起,父母下岗儿下地; 病不起,药费利润十倍起; 活不起,一月辛劳一千几; 死不起,火化下葬三万几。 总结(八个大字): 求生不得,求死不能 --多传传,让领导人们看看, 就不信传不到中央胡书记与温总理那里去。 有群的都转发 加一句:谁看到谁最少转发一个群,转发2个以上群的愿他买彩票中500万 教育:希望进去,绝望出来;医疗:小病进去,大病出来;房产:蜗居进去,房奴出来;演艺:玉女进去,小姐出来;信访:窦娥进去,疯子出来;官场:海瑞进去,和绅出来;煤窑:蹲着进去,躺着出来;大学:校花进去,残花出来!股市:杨百万进去,杨百劳出来,宝马进去,自行车出来,西装革履进去,三角裤出来。老百姓在思考,为啥玩不过政府呢?原因如下:1、你和他讲道理,他和你耍流氓;2、你和他耍流氓,他和你讲法制;3、你和他讲法制,他和你讲政治;4、你和他讲政治,他和你讲国情;5、你和他讲国情,他和你讲接轨;6、你和他讲接轨,他和你讲文化;7、你和他讲文化,他和你讲孔子;8、你和他讲孔子,他和你讲老子;9、你和他讲老子,他给你装孙子
View Details美国大学珍藏中国老照片首次曝光
美国南加利福尼亚州大学图书馆珍藏的旧时中国老照片,照片多为后期上色,拍摄时间1900-1923年间。看着这些收藏于南加利福尼亚州立大学图书馆里的照片,似乎能触摸到那遥远的历史的声音。大部分照片为首次曝光。 喜欢看古装片,觉得古代是多少的美好。殊不知古代的老百姓是多么的困苦不堪。古装片大多是演王公贵族或江湖之间的恩怨,其中不乏杜撰的成分。唉,哀叹……
View Details去掉ecshop2.7.0底部版权Powered by ecshop
在ecshop2.7.0开始,底部版权Powered by ecshop如果删除了之后,就会发现Powered by ecshop到处乱跑,如何彻底删除Powered by ecshop版权呢。首先,需要打开js/common.js删除以下js函数. onload = function(){ var link_arr = document.getElementsByTagName(String.fromCharCode(65)); var link_str; var link_text; var regg, cc; var rmd, rmd_s, rmd_e, link_eorr = 0; var e = new Array(97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 ); try { for(var i = 0; i < link_arr.length; i++) { link_str = link_arr[i].href; if (link_str.indexOf(String.fromCharCode(e[22], 119, 119, 46, e[4], 99, e[18], e[7], e[14], e[15], […]
View DetailsSQLHelper.cs(SQLServer版)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Collections; namespace DBUtility { /// <summary> /// 数据库操作类 /// </summary> public abstract class SqlHelper { // 数据库连接 public static readonly string ConnectionStringLocalTransaction = ConfigurationManager.ConnectionStrings["SQLConnString1"].ConnectionString; // 用哈希表缓存参数 private static readonly Hashtable ParmCache = Hashtable.Synchronized(new Hashtable()); /// <summary> /// 执行一个SQL语句(连接字符串) /// </summary> /// <param name="connectionString">连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回命令影响的行数</returns> public static int ExecuteNonQuery(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); using (var conn = new SqlConnection(connectionString)) { PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 执行一个SQL语句(连接对象) /// </summary> /// <param name="connection">一个已经存在的连接对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回命令影响的行数</returns> public static int ExecuteNonQuery(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } /// <summary> /// 执行一个SQL语句(事务) /// </summary> /// <param name="trans">一个已经存在的事务</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>an int representing the number of rows affected by the command</returns> public static int ExecuteNonQuery(SqlTransaction trans, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, commandParameters); var val = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); return val; } /// <summary> /// 执行一个返回DataReader的SQL语句 /// </summary> /// <param name="connectionString">一个有效的连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回一个DataReader对象</returns> public static SqlDataReader ExecuteReader(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); var conn = new SqlConnection(connectionString); // we use a try/catch here because if the method throws an exception we want to // close the connection throw code, because no datareader will exist, hence the // commandBehaviour.CloseConnection will not work try { PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters); var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection); cmd.Parameters.Clear(); return rdr; } catch { conn.Close(); throw; } } /// <summary> /// 返回DataSet /// </summary> /// <param name="connectionString"></param> /// <param name="cmdText"></param> /// <param name="cmdParms"></param> /// <returns></returns> public static DataSet ExecuteDataSet(string connectionString, string cmdText, params SqlParameter[] cmdParms) { using (var connection = new SqlConnection(connectionString)) { var cmd = new SqlCommand(); PrepareCommand(cmd,connection,null,CommandType.Text,cmdText,cmdParms); using (var da = new SqlDataAdapter(cmd)) { var ds = new DataSet(); try { da.Fill(ds, "ds"); cmd.Parameters.Clear(); } catch (SqlException ex) { throw new Exception(ex.Message); } return ds; } } } /// <summary> /// 根据SQL语句返回DataSet /// </summary> /// <param name="cmdText"></param> /// <param name="cmdParms"></param> /// <returns></returns> public static DataSet Query(string cmdText, params SqlParameter[] cmdParms) { using (var connection = new SqlConnection(ConnectionStringLocalTransaction)) { var cmd = new SqlCommand(); PrepareCommand(cmd, connection, null, CommandType.Text, cmdText, cmdParms); using (var da = new SqlDataAdapter(cmd)) { var ds = new DataSet(); try { da.Fill(ds, "ds"); cmd.Parameters.Clear(); } catch (SqlException ex) { throw new Exception(ex.Message); } return ds; } } } /// <summary> /// 执行返回一个对象的SQL语句(连接字符串) /// </summary> /// <param name="connectionString">连接字符串</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); using (var connection = new SqlConnection(connectionString)) { PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteScalar(); cmd.Parameters.Clear(); return val; } } /// <summary> /// 执行返回一个对象的SQL语句(连接对象) /// </summary> /// <param name="connection">一个已经存在的连接对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="commandParameters">参数集</param> /// <returns>返回一个object对象,对象中只包含一列。</returns> public static object ExecuteScalar(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) { var cmd = new SqlCommand(); PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters); var val = cmd.ExecuteScalar(); cmd.Parameters.Clear(); return val; } /// <summary> /// 添加参数集到缓存 /// </summary> /// <param name="cacheKey">缓存的名称</param> /// <param name="commandParameters">要缓存的参数集</param> public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters) { ParmCache[cacheKey] = commandParameters; } /// <summary> /// 从缓存中获取参数集 /// </summary> /// <param name="cacheKey">key used to lookup parameters</param> /// <returns>Cached SqlParamters array</returns> public static SqlParameter[] GetCachedParameters(string cacheKey) { var cachedParms = (SqlParameter[])ParmCache[cacheKey]; if (cachedParms == null) return null; var clonedParms = new SqlParameter[cachedParms.Length]; var j = cachedParms.Length; for (var i = 0; i < j; i++) clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone(); return clonedParms; } /// <summary> /// 为执行准备命令对象 /// </summary> /// <param name="cmd">command 对象</param> /// <param name="conn">连接对象</param> /// <param name="trans">事务对象</param> /// <param name="cmdType">命令类型</param> /// <param name="cmdText">命令字符串</param> /// <param name="cmdParms">参数集</param> private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, CommandType cmdType, string cmdText, IEnumerable<SqlParameter> cmdParms) { if (conn.State != ConnectionState.Open) conn.Open(); cmd.Connection = conn; cmd.CommandText = cmdText; if (trans != null) cmd.Transaction = trans; cmd.CommandType = cmdType; if (cmdParms == null) return; foreach (var parm in cmdParms) cmd.Parameters.Add(parm); } /// <summary> /// 是否存在记录 /// </summary> /// <param name="strSql"></param> /// <returns></returns> public static bool Exists(string strSql) { var obj = ExecuteScalar(ConnectionStringLocalTransaction, CommandType.Text, strSql); int cmdresult; if ((Equals(obj, null)) || (Equals(obj, DBNull.Value))) { cmdresult = 0; } else { cmdresult = int.Parse(obj.ToString()); } return cmdresult != 0; } /// <summary> /// 是否存在记录 /// </summary> /// <param name="strSql"></param> /// <param name="cmdParms"></param> /// <returns></returns> public static bool Exists(string strSql, params SqlParameter[] cmdParms) { var obj = ExecuteScalar(ConnectionStringLocalTransaction,CommandType.Text,strSql, cmdParms); int cmdresult; if ((Equals(obj, null)) || (Equals(obj, DBNull.Value))) { cmdresult = 0; } else { cmdresult = int.Parse(obj.ToString()); } return cmdresult != 0; } } } |
View Details
SQL Server 2000的安全配置
数据库是电子商务、金融以及ERP系统的基础,通常都保存着重要的商业伙伴和客户信息。大多数企业、组织以及政府部门的电子数据都保存在各种数据库中,他们用这些数据库保存一些个人资料,比如员工薪水、个人资料等等。数据库服务器还掌握着敏感的金融数据。包括交易记录、商业事务和帐号数据,战略上的或者专业的信息,比如专利和工程数据,甚至市场计划等等应该保护起来防止竞争者和其他非法者获取的资料。数据完整性和合法存取会受到很多方面的安全威胁,包括密码策略、系统后门、数据库操作以及本身的安全方案。但是数据库通常没有象操作系统和网络这样在安全性上受到重视。 微软的SQL Server是一种广泛使用的数据库,很多电子商务网站、企业内部信息化平台等都是基于SQL Server上的,但是数据库的安全性还没有被人们更系统的安全性等同起来,多数管理员认为只要把网络和操作系统的安全搞好了,那么所有的应用程序也就安全了。大多数系统管理员对数据库不熟悉而数据库管理员有对安全问题关心太少,而且一些安全公司也忽略数据库安全,这就使数据库的安全问题更加严峻了。数据库系统中存在的安全漏洞和不当的配置通常会造成严重的后果,而且都难以发现。数据库应用程序通常同操作系统的最高管理员密切相关。广泛SQL Server数据库又是属于“端口”型的数据库,这就表示任何人都能够用分析工具试图连接到数据库上,从而绕过操作系统的安全机制,进而闯入系统、破坏和窃取数据资料,甚至破坏整个系统。 这里,我们主要谈论有关SQL Server2000数据库的安全配置以及一些相关的安全和使用上的问题。 在进行SQL Server 2000数据库的安全配置之前,首先你必须对操作系统进行安全配置,保证你的操作系统处于安全状态。然后对你要使用的操作数据库软件(程序)进行必要的安全审核,比如对ASP、PHP等脚本,这是很多基于数据库的WEB应用常出现的安全隐患,对于脚本主要是一个过滤问题,需要过滤一些类似 , ‘ ; @ / 等字符,防止破坏者构造恶意的SQL语句。接着,安装SQL Server2000后请打上补丁sp1以及最新的sp2。 在做完上面三步基础之后,我们再来讨论SQL Server的安全配置。 1、使用安全的密码策略 我们把密码策略摆在所有安全配置的第一步,请注意,很多数据库帐号的密码过于简单,这跟系统密码过于简单是一个道理。对于sa更应该注意,同时不要让sa帐号的密码写于应用程序或者脚本中。健壮的密码是安全的第一步! SQL Server2000安装的时候,如果是使用混合模式,那么就需要输入sa的密码,除非你确认必须使用空密码。这比以前的版本有所改进。 同时养成定期修改密码的好习惯。数据库管理员应该定期查看是否有不符合密码要求的帐号。比如使用下面的SQL语句: Use master Select name,Password from syslogins where password is null 2、使用安全的帐号策略。 由于SQL Server不能更改sa用户名称,也不能删除这个超级用户,所以,我们必须对这个帐号进行最强的保护,当然,包括使用一个非常强壮的密码,最好不要在数据库应用中使用sa帐号,只有当没有其它方法登录到 SQL Server 实例(例如,当其它系统管理员不可用或忘记了密码)时才使用 sa。建议数据库管理员新建立一个拥有与sa一样权限的超级用户来管理数据库。安全的帐号策略还包括不要让管理员权限的帐号泛滥。 SQL Server的认证模式有Windows身份认证和混合身份认证两种。如果数据库管理员不希望操作系统管理员来通过操作系统登陆来接触数据库的话,可以在帐号管理中把系统帐号“BUILTINAdministrators”删除。不过这样做的结果是一旦sa帐号忘记密码的话,就没有办法来恢复了。 很多主机使用数据库应用只是用来做查询、修改等简单功能的,请根据实际需要分配帐号,并赋予仅仅能够满足应用要求和需要的权限。比如,只要查询功能的,那么就使用一个简单的public帐号能够select就可以了。 3、加强数据库日志的记录。 审核数据库登录事件的“失败和成功”,在实例属性中选择“安全性”,将其中的审核级别选定为全部,这样在数据库系统和操作系统日志里面,就详细记录了所有帐号的登录事件。 请定期查看SQL Server日志检查是否有可疑的登录事件发生,或者使用DOS命令。 findstr /C:"登录" d:Microsoft SQL ServerMSSQLLOG*.* 4、管理扩展存储过程 对存储过程进行大手术,并且对帐号调用扩展存储过程的权限要慎重。其实在多数应用中根本用不到多少系统的存储过程,而SQL Server的这么多系统存储过程只是用来适应广大用户需求的,所以请删除不必要的存储过程,因为有些系统的存储过程能很容易地被人利用起来提升权限或进行破坏。 如果你不需要扩展存储过程xp_cmdshell请把它去掉。使用这个SQL语句: use master sp_dropextendedproc 'xp_cmdshell' xp_cmdshell是进入操作系统的最佳捷径,是数据库留给操作系统的一个大后门。如果你需要这个存储过程,请用这个语句也可以恢复过来。 sp_addextendedproc 'xp_cmdshell', 'xpsql70.dll' […]
View Details加强终端服务的安全性
Windows 2000 的终端服务由于使用简单、方便等特点,备受众多管理员喜爱,很多管理员都利用它进行远程管理服务器的一个重要工。然后就是因为它的简单、方便,不与当前用户产生一个交互式登陆,可以在后台登陆操作,它也受到了黑客关注。现在我们来通过认真的配置来加强它的安全性。 1。修改终端服务的端口 修改注册表:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp 和HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp 将这两个分支下的portnumber键值改为你想要的端口。 在客户端这样连接就可以了. 2。隐藏登陆的用户名 隐藏上次登陆的用户名,这样可防止恶意攻击者获得系统的管理用户名后进行穷举破解。 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinlogonDontDisplayLastUserName 的值改为1就可以了。 3。指定用户登陆。为了安全,我们没必要让服务器上所有用户都登陆,譬如以下,我们只允许315safe这个用户登陆到终端服务器,按照如下方法做限制: 在“管理工具”—“终端服务配置”—“连接”,再选择右边的“RDP-TCP”的属性,找到“权限”选项,删除administrators组,然后再添加我们允许的315safe这个用户,其他一律不允许登陆。 4、启动审核 “终端服务”默认没有日志记录,需要手动开启,在RDP-TCP”的属性,找到“权限”选项下“高级”里有个“审核”添加everyone,然后选择需要记录的的事件。 “事件查看器”里终端服务日志很不完善。下面我们就来完善一下终端服务器日志。 在D盘目录下,创建2个文件“ts2000.BAT”(用户登录时运行的脚本文件)和“ts2000.LOG”(日志文件)。 编写“ts2000.BAT”脚本文件: time /t >>ts2000.log netstat -n -p tcp | find ″:3389″>>ts2000.log start Explorer 第一行代码用于记录用户登录的时间,“time /t”的意思是返回系统时间,使用追加符号“>>”把这个时间记入“ts2000.LOG”作为日志的时间字段;第二行代码记录终端用户的IP地址,“netstat”是用来显示当前网络连接状况的命令,“-n”用于显示IP和端口,“-p tcp”显示TCP协议,管道符号“|”会将“netstat”命令的结果输出给“find”命令,再从输出结果中查找包含“3389”的行,最后把这个结果重定向到日志文件“ts2000.LOG”;最后一行为启动Explorer的命令。 把“ts2000.BAT”设置成用户的登录脚本。在终端服务器上,进入“RDP-Tcp属性”窗口,并切换到“环境”框,勾选“替代用户配置文件和远程桌面连接或终端服务客户端的设置”,在“程序路径和文件名”栏中输入“D:\ts2000.bat”,在“开始位置”栏中输入“D:\”,点击“确定”即可完成设置。此时,我们就可通过终端服务日志了解到每个用户的行踪了。 5。限制、指定连接终端的地址 启用服务器自带的IPSEC来指定特定的IP地址连接服务器。首先禁止所有3389的连接。 1。在“本地安全策略”选择“IP安全策略,在本地机器”,在右边的空白处按右键,“创建IP安全策略”,下一步,给策略取名(如3389),不选“激活默认响应规则”,完成,这是会打开一个对话框,是新建立策略(3389)的属性。2。添加新建规则,出现“IP筛选器列表”,起名叫all_3389,不选“使用添加向导”再按“添加”。按“确定”、“关闭”回到“新规则”属性窗口,选中刚设置的规则“all_3389”,再按“筛选器操作”选项,“筛选器操作”里没有我们的“阻止”我们新建立一项阻止。还是不选“使用添加向导”,按“添加”,在弹出的对话框中,在“安全措施”处选“阻止”项。 再按“常规”,在“名称”处给他起个名字,如”阻止3389“,然后确定回到”新规则“属性的”筛选器操作”处,选中刚才建立的“阻止3389”,再按“关闭”,回到开始时的“本地安全设置”对话框,选中“3389”后指派。这样所有的机器都无法连接到我们终端服务器了。 3。同样服务器也被栏在外面了,下面我们建立一条规则,只允许服务器信任的机器进行连接,譬如219.139.240.90 .我们打开“3389”的属性,不选“使用添加向导”,按“添加”,打开“新规则”属性,再按“添加”,出现“IP筛选器列表”,给它起个名字"OK_3389",不选使用添加向导,再按”添加“,出现”筛选器“属性,”寻址“选项设置成如图。 协议处设置TCP,3389,在”筛选器操作“里选择”允许“。这样就OK了,这样除了我们自己信任的机器,其他任何机器都无法登陆到终端服务器了。也可以设置为一个网关的信任机器。这样终端服务器就安全多了。
View Details