每天学一点网站安全相关的小知识
文章目录
- 网站中的常见的安全问题
- SQL注入漏洞
- Mybatis框架下易产生SQL注入漏洞场景分析
- XSS 攻击
- CSRF 攻击
- 密码学
- 数字签名(digital signature)和 数字证书(digital certificate)
- 认证、授权、凭证
- 认证
- 授权
- 凭证
- 常常使用的几种认证和授权技术
- HTTP Basic Authentication
- HMAC(AK/SK)认证
- JWT– JSON Web Tokens
- OAuth 1.0
- OAuth 2.0
网站中的常见的安全问题
SQL注入漏洞
SQL注入问题比较常规,但确实大部分网站中容易存在的网络安全漏洞。SQL注入的原理是用户通过非正常输入(修改URL或者表单数据)把恶意的 SQL 命令插入到 Web 表单让服务器执行,最终达到欺骗服务器或数据库执行恶意的 SQL 命令。
解决方法:
- 过滤特殊字符
- 不使用字符串拼接,使用JDBC预编译模式
- 使用框架(其中Mybatis 就是使用了JDBC预编译模式)
Mybatis框架下易产生SQL注入漏洞场景分析
- 模糊查询like
还以第一节中提到的新闻详情页面为例, 按照新闻标题对新闻进行模糊查询,如果考虑安全编码规范问题,其对应的SQL语句如下:Select * from news where title like ‘%#{title}%’,但由于这样写程序会报错,研发人员将SQL查询语句修改如下:Select * from news where title like ‘%${title}%’,在这种情况下我们发现程序不再报错,但是此时产生了SQL语句拼接问题,如果java代码层面没有对用户输入的内容做处理势必会产生SQL注入漏洞。
- in之后的参数
在对新闻进行同条件多值查询的时候 ,如当用户输入1001,1002,1003…100N时,如果考虑安全编码规范问题,其对应的SQL语句如下:Select * from news where id in (#{id}),但由于这样写程序会报错,研发人员将SQL查询语句修改如下:Select * from news where id in (${id}),修改SQL语句之后,程序停止报错,但是却引入了SQL语句拼接的问题,如果研发人员没有对用户输入的内容做过滤,势必会产生SQL注入漏洞。
- order by之后
当根据发布时间、点击量等信息对新闻进行排序的 时候,如果考虑安全编码规范问题,其对应的SQL语句如下:Select * from news where title =‘京东’ order by #{time} asc,但由于发布时间time不是用户输入的参数,无法使用预编译。研发人员将SQL查询语句修改如下:Select * from news where title =‘京东’ order by ${time} asc,修改之后,程序通过预编译,但是产生了SQL语句拼接问题,极有可能引发SQL注入漏洞。
解决方式都是采用预编译机制,避免了SQL语句拼接的问题,从根源上防止了SQL注入漏洞的产生。
参考: mybatis之SQL注入漏洞及防护措施
MyBatis SQL注入隐患及防范
Mybatis 框架下 SQL 注入攻击的 3 种方式,真是防不胜防!
XSS 攻击
XSS 攻击,即跨站脚本攻击(Cross Site Scripting),它是 web 程序中常见的漏洞。 原理是攻击者往 web 页面里插入恶意的脚本代码(CSS代码、JavaScript代码等),当用户浏览该页面时,嵌入其中的脚本代码会被执行,从而达到恶意攻击用户的目的。如盗取用户cookie,破坏页面结构、重定向到其他网站等。
预防方法:
- 永远不要相信用户的输入,必须对输入的数据作过滤处理。
- 前端框架的React.js 和Vue.js 默认会对渲染的内容进行转义
- 后端也需要对请求的数据进行校验或者过滤
参考:前端安全系列(一):如何防止XSS攻击?
CSRF 攻击
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
一个典型的CSRF攻击有着如下的流程:
- 受害者登录a.com,并保留了登录凭证(Cookie)。
- 攻击者引诱受害者访问了b.com。
- b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。
- a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
- a.com以受害者的名义执行了act=xx。
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。
CSRF通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对CSRF的防护能力来提升安全性。
CSRF的两个特点:
- CSRF(通常)发生在第三方域名。
- CSRF攻击者不能获取到Cookie等信息,只是使用。
预防方法:
阻止不明外域的访问
同源检测
既然CSRF大多来自第三方网站,那么我们就直接禁止外域(或者不受信任的域名)对我们发起请求。
CSRF大多数情况下来自第三方域名,但并不能排除本域发起。如果攻击者有权限在本域发布评论(含链接、图片等,统称UGC),那么它可以直接在本域发起攻击,这种情况下同源策略无法达到防护的作用。
综上所述:同源验证是一个相对简单的防范方法,能够防范绝大多数的CSRF攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。
Samesite Cookie
提交时要求附加本域才能获取的信息
- CSRF Token
- 用户打开页面的时候,服务器需要给这个用户生成一个Token,该Token通过加密算法对数据进行加密,显然在提交时Token不能再放在Cookie中了,否则又会被攻击者冒用。当用户从客户端得到了Token,再次提交给服务器的时候,服务器需要判断Token的有效性,验证过程是先解密Token,对比加密字符串以及时间戳,如果加密字符串一致且时间未过期,那么这个Token就是有效的。
- Token是一个比较有效的CSRF防护方法,只要页面没有XSS漏洞泄露Token,那么接口的CSRF攻击就无法成功。
- 双重Cookie验证
- 利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。
- CSRF Token
参考:前端安全系列(二):如何防止CSRF攻击?
Cookie 的 SameSite 属性
SameSite Cookie,防止 CSRF 攻击
密码学
加密方法可以分为两大类。一类是单钥加密(private key cryptography),还有一类叫做双钥加密(public key cryptography)
通用的单钥加密算法为DES(Data Encryption Standard),通用的双钥加密算法为RSA( Rivest-Shamir-Adleman)
在单钥加密的情况下,密钥只有一把,所以密钥的保存变得很重要。一旦密钥泄漏,密码也就被破解
在双钥加密的情况下,密钥有两把,一把是公开的公钥,还有一把是不公开的私钥。
双钥加密的原理如下:
a) 公钥和私钥是一一对应的关系,有一把公钥就必然有一把与之对应的、独一无二的私钥,反之亦成立。
b) 所有的(公钥, 私钥)对都是不同的。
c) 用公钥可以解开私钥加密的信息,反之亦成立。
d) 同时生成公钥和私钥应该相对比较容易,但是从公钥推算出私钥,应该是很困难或者是不可能的。
在双钥体系中,公钥用来加密信息,私钥用来数字签名。
不要去硬记。
你只要想:既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。
参考:密码学笔记
RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?
数字签名(digital signature)和 数字证书(digital certificate)
用大白话来举例子:
- 小明搞了一把公钥和一把私钥,他跟小红关系好,他把公钥给了小红,当然他还可以把公钥给其他好多人。
- 小红想给小明写一封保密信,她用公钥加密了发给了小明。
- 只有小明有私钥,所以这份信只有小明能读懂,其他人读不懂,只要小明的私钥保管好。(所以这里也就是为什么上面说的,公钥用来加密,因为一般情况下公钥是公开的可以多个人拥有的,而私钥是保密的。所以如果消息想要保密,就用公钥加密,因为只有私钥能解密。如果用私钥加密,拥有公钥的人都能解开了。 所以公钥一般用于加密消息)
- 现在小明想回信给小红,想使用数字签名的方式。 所以他先把信写完,然后对信的内容使用Hash函数生成一个摘要(digest),然后小明再对这个摘要用私钥进行加密得到一个数字签名(我们可以把它想象成为小明的名字的签名),然后把这个数字签名还有信的内容一起发送给小红
- 小红收到信之后,首先看数字签名,对数字签名用公钥解密,得到摘要,然后在对信的内容进行Hash,然后比对Hash后的内容和摘要是否一致,如果一致就说明这封信确实是小明写的,没有被改过。(可以简单的理解为,小红不知道小明的字迹是怎样的,但是小明给了一张字迹的照片给小红。通过这个照片可以确定小明的字迹,所以这要这封信的签名的字迹是小明的,那我们就可以认定这份信是小明写的了)
- 现在出了一个新人物小张,他偷了小红的公钥,换成了自己的公钥。现在小红的公钥就不是小明给的了,而是小张给的了。(相当于小张把小明字迹的照片偷走了,换成了他自己字迹的照片,所以现在小红对照字迹的照片是小张的。所以现在小红不认识小明的字迹了,只认识小张的字迹了)。现在小张就可以冒充小明给小红发消息了。
- 小红觉得不太对劲,发现自己的公钥不确定是否是属于小明的。所以她想到一个方法。就是让小明去"证书中心"(certificate authority,简称CA),为公钥做认证。 证书中心用自己的私钥对小明的公钥和其他信息进行加密,生成数字证书(Digital Certificate),小明拿到数字证书之后,以后给小红写信就需要在签名的同时附上数字证书。
- 然后小红收到信之后,通过CA的公钥去解开数字证书,拿到小明的公钥,然后通过公钥去解密数字签名,就可以知道这个信是不是小明写的了。(相当于有一个权威的公证中心,拥有小明字迹的照片,公开给所有人,所有人都知道小明的字迹,所以你就算换了照片就会被别人发现。所以现在这个小明字迹的照片是真实正确的,所以自然比对的字迹就是小明的了)
参考:数字签名是什么?
认证、授权、凭证
认证
认证是 authentication,指的是当前用户的身份,当用户登陆过后系统便能追踪到他的身份做出符合相应业务逻辑的操作。即使用户没有登录,大多数系统也会追踪他的身份,只是当做来宾或者匿名用户来处理。认证技术解决的是**“我是谁?”**的问题。
授权
授权则不同,授权是 authorization,指的是什么样的身份被允许访问某些资源,在获取到用户身份后继续检查用户的权限。授权技术是解决"**“我能做什么?”**的问题。
凭证
实现认证和授权的基础是需要一种媒介(credentials)来标记访问者的身份或权利,在现实生活中每个人都需要一张身份证才能访问自己的银行账户,这就是认证的凭证
在互联网世界中,服务器为每一个访问者颁发 session ID 存放到 cookie,这就是一种凭证技术。数字凭证还表现在方方面面,SSH 登录的密匙、JWT 令牌、一次性密码等。
下面我会介绍在API开发中常常使用的几种认证和授权技术:HTTP Basic Authentication、HAMC、OAuth2,以及凭证技术JWT token。
常常使用的几种认证和授权技术
HTTP Basic Authentication
- 组合用户名和密码然后 Base64 编码
- 给编码后的字符串添加 Basic 前缀,然后设置名称为 Authorization 的 header 头部
API 也可以非常简单的提供 HTTP Basic Authentication 认证方式,那么客户端可以很简单通过 Base64 传输用户名和密码即可:
- 将用户名和密码使用冒号连接,例如 username:abc123456
- 为了防止用户名或者密码中存在超出 ASCII 码范围的字符,推荐使用UTF-8编码
- 将上面的字符串使用 Base 64 编码,例如 dXNlcm5hbWU6YWJjMTIzNDU2
- 在 HTTP 请求头中加入 “Basic + 编码后的字符串”,即:Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
这种方式实现起来非常简单,在大量场景下被采用。当然缺点也很明显,Base64 只能称为编码,而不是加密 (实际上无需配置密匙的客户端并没有任何可靠地加密方式,我们都依赖 TSL 协议)。这种方式的致命弱点是编码后的密码如果明文传输则容易在网络传输中泄露,在密码不会过期的情况下,密码一旦泄露,只能通过修改密码的方式。
HMAC(AK/SK)认证
HMAC技术,是一种用于给消息签名的技术,也就是说,我们怕消息在传递的过程中被人修改,所以,我们需要用对消息进行一个MAC算法,得到一个摘要字串,然后,接收方得到消息后,进行同样的计算,然后比较这个MAC字符串,如果一致,则表明没有被修改过。
基本过程如下:
客户端需要在认证服务器中预先设置 access key(AK 或叫 app ID) 和 secure key(SK)
在调用 API 时,客户端需要对参数和 access key 进行自然排序后并使用 secure key 进行签名生成一个额外的参数 digest
服务器根据预先设置的 secure key 进行同样的摘要计算,并要求结果完全一致
注意 secure key 不能在网络中传输,以及在不受信任的位置存放(浏览器等)
JWT– JSON Web Tokens
JWT是一个比较标准的认证解决方案,这个技术在Java圈里应该用的是非常普遍的.
JWT 是一种包含令牌(self-contained token),或者叫值令牌 (value token),我们以前使用关联到 session 上的 hash 值被叫做引用令牌(reference token)。
引用toekn:比如sessionId,流程如下:
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
这种模式的问题在于,扩展性(不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。
另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。
值token:比如JWT,是业界对 token 做了进一步优化,设计了一种自包含令牌,令牌签发后无需从服务器存储中检查是否合法,通过解析令牌就能获取令牌的过期、有效等信息,这就是JWT (JSON Web Token)。
JWT的签名流程一般是下面这个样子:
- JWT的内容分为三个部分,分别为Header(头部),Payload(负载),Signature(签名)
- 服务器认证以后,生成一个 JSON 对象,就像下面这样,然后通过base64处理之后作为JWT的Payload部分
{"姓名": "张三","角色": "管理员","到期时间": "2018年7月1日0点0分"
}
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{"alg": "HS256","typ": "JWT" }
上面代码中,
alg
属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ
属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
Signature (签名)部分是对前两部分的签名,防止数据篡改。首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(
.
)分隔,就可以返回给用户。
当应用服务器收到请求后:
- 应用服务会检查 JWT Token,确认签名是正确的。
- 然而,因为只有认证服务器有这个用户的Secret Key(密钥),所以,应用服务器得把JWT Token传给认证服务器。
- 认证服务器通过JWT Payload 解出用户的抽象ID,然后通过抽象ID查到登录时生成的Secret Key,然后再来检查一下签名。
- 认证服务器检查通过后,应用服务就可以认为这是合法请求了。
我们可以看以,上面的这个过程,是在认证服务器上为用户动态生成 Secret Key的,应用服务在验签的时候,需要到认证服务器上去签,这个过程增加了一些网络调用,所以,JWT除了支持HMAC-SHA256的算法外,还支持RSA的非对称加密的算法。
使用RSA非对称算法,在认证服务器这边放一个私钥,在应用服务器那边放一个公钥,认证服务器使用私钥加密,应用服务器使用公钥解密。这样一来,就不需要应用服务器向认证服务器请求了,但是,RSA是一个很慢的算法,所以,虽然你省了网络调用,但是却费了CPU,尤其是Header和Payload比较长的时候。
更好的解决方法是, 我们把header 和 payload简单地做SHA256,啪的一下很快啊,然后,我们用RSA加密这个SHA256出来的字符串,这样一来,RSA算法就比较快了,而我们也做到了使用RSA签名的目的。
最后,我们只需要使用一个机制在认证服务器和应用服务器之间定期地换一下公钥私钥对就好了。
OAuth 1.0
OAuth也是一个API认证的协议, 2010年4月,正式发布OAuth 1.0。 OAuth 的出现,目的是为了,用户为了想使用一个第三方的网络打印服务来打印他在某网站上的照片,但是,用户不想把自己的用户名和口令交给那个第三方的网络打印服务,但又想让那个第三方的网络打印服务来访问自己的照片,为了解决这个授权的问题,OAuth这个协议就出来了。
这个协议有三个角色:
- User(照片所有者-用户): 照片在照片存储服务中,但是用户拥有使用权
- Consumer(第三方照片打印服务):第三方的打印服务想要拿到照片存储服务中的照片进行打印,所以是消费者
- Service Provider(照片存储服务):照片存储服务需要提供照片的接口给第三方打印服务去获取,所以是提供者
这个协义有三个阶段:
- Consumer获取Request Token
- Service Provider 认证用户并授权Consumer
- Consumer获取Access Token调用API访问用户的照片
整个授权过程是这样的:
- Consumer(第三方照片打印服务)需要先上Service Provider获得开发的 Consumer Key 和 Consumer Secret。也就是获取到了上面说的AK和SK,用于对请求签名
- 当 User 访问 Consumer 时,Consumer 向 Service Provide 发起请求,请求Request Token (需要对HTTP请求签名,这样Service Provide 需要进行验签,才能确认请求是Consumer发来的)
- Service Provide 验明 Consumer 是注册过的第三方服务商后,返回 Request Token(
oauth_token
)和 Request Token Secret (oauth_token_secret
)用于后面签名使用 - Consumer 收到 Request Token 后,使用HTTP GET 请求把 User 切到 Service Provide 的认证页上(其中带上Request Token),让用户输入他的用户和口令。
- Service Provider 认证 User 成功后,跳回 Consumer,并返回 Request Token (
oauth_token
)和 Verification Code(oauth_verifier
) - 接下来就是签名请求,用Request Token 和 Verification Code 换取 Access Token (
oauth_token
)和 Access Token Secret (oauth_token_secret
) - 最后使用Access Token 访问用户授权访问的资源。
因为上面这个流程有三方:User,Consumer 和 Service Provide,所以,又叫 3-legged flow,三脚流程。OAuth 1.0 也有不需要用户参与的,只有Consumer 和 Service Provider 的, 也就是 2-legged flow 两脚流程,其中省掉了用户认证的事。
整个过程如下所示:
- Consumer(第三方照片打印服务)需要先上Service Provider获得开发的 Consumer Key 和 Consumer Secret
- Consumer 向 Service Provide 发起请求请求Request Token (需要对HTTP请求签名)
- Service Provide 验明 Consumer 是注册过的第三方服务商后,返回 Request Token(
oauth_token
)和 Request Token Secret (oauth_token_secret
) - Consumer 收到 Request Token 后,直接换取 Access Token (
oauth_token
)和 Access Token Secret (oauth_token_secret
) - 最后使用Access Token 访问用户授权访问的资源。
OAuth 2.0
OAuth 1.0,这些个API认证都是要向Client发一个密钥(或是用密码)然后用HASH或是RSA来签HTTP的请求,这其中有个主要的原因是,以前的HTTP是明文传输,所以,在传输过程中很容易被篡改,于是才搞出来一套的安全签名机制。
OAuth 2.0依赖于TLS/SSL的链路加密技术(HTTPS),完全放弃了签名的方式,认证服务器再也不返回什么 token secret 的密钥了,所以,OAuth 2.0是完全不同于1.0 的,也是不兼容的。
大白话讲解OAuth的设计
- 小明住在一个小区里,小区里面有门禁系统(相当于认证),进入的时候需要输入密码才能进入(才能登陆进小区)
- 但是小明经常点外卖,外卖配送员不是小区的业主,他不知道密码,小明也不能告诉他密码,万一外卖配送员哪天转行小偷了就能通过密码进来了,这样就不安全了,小明不想让他进来的话还要改密码就太麻烦了,而且改完密码还要告诉其他的快递小哥,我的密码换了。麻烦的事情太多了。
- 那有没有办法让外卖小哥和快递小哥能够自由进出小区又不需要知道小区的密码,而他唯一能够做的就只有送货,小区其他地方需要使用密码的地方他都去不了。
- 于是小区就设计了一套授权机制(开发了授权服务),以后外卖小哥来到小区门口,就对这个门禁系统进行操作,就按小明住的对应的门牌号,然后小明的手机就会弹出对话框,告诉小明正在有人想要进入小区,系统还会显示这个外卖小哥是谁,叫什么。然后小明同意之后,就相当于告诉系统,同意授予外卖小哥进入小区的权利了。
- 门禁系统得到小明的确认之后,就会给快递员发一个小区的令牌,这个令牌只有在一段时间内有效,比如七天有效。
- 然后快递员只要向门禁系统输入令牌,就可以进入小区了。
- 有人可能会问,为什么不是远程为快递员开门,而要为他单独生成一个令牌?因为麻烦。。 这是因为快递员可能每天都会来送货,第二天他还可以复用这个令牌。另外,有的小区有多重门禁,快递员可以使用同一个令牌通过它们。
对应互联网上的场景如下:
首先,居民小区就是储存用户数据的网络服务。比如,微信储存了我的好友信息,获取这些信息,就必须经过微信的"门禁系统"。
其次,快递员(或者说快递公司)就是第三方应用,想要穿过门禁系统,进入小区。
最后,我就是用户本人,同意授权第三方应用进入小区,获取我的数据。
简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
参考: 细说API – 认证、授权和凭证
HTTP API 认证授权术
Cookie、Session是如何保持登录状态的?
JSON Web Token 入门教程
理解OAuth 2.0
OAuth 2.0 的一个简单解释
每天学一点网站安全相关的小知识相关推荐
- 学平面设计要掌握哪些小知识?
本文由:"学设计上兔课网"原创,图片素材来自网络,仅供学习分享 学平面设计要掌握哪些小知识?平面设计也称为视觉传达设计,是以"视觉"作为沟通和表现的方式,透过多 ...
- 网站开发的小知识参考(慢慢收集备用)
inetinfo.exe占用80端口的解决方法 我在本机配置PHP环境时,安装的时候遇到80端口被占用,经过查询才知道,原来是Inetinfo.exe占用了80端口,于是把Inetinfo.exe服务 ...
- 【Java】每日一点Java小知识 --- day6
每日一点Java基础小知识 - day6 欢迎来到叮当猫学编程的Java基础小知识系列~在这里,你将会看到叮当猫每日关于Java的基础知识总结,欢迎大家的点赞关注喔 方法重载: 被重载的方法必须改变参 ...
- 网络安全你必须知道的100个小知识
网络安全风险无处不在,信服君为大家梳理了100个网络安全相关的小知识,希望能进一步提升大家的安全意识,帮助大家建立更加安全的网络环境. 网络安全入门学习路线 其实入门网络安全要学的东西不算 ...
- 网站前端开发基础知识学什么?必备技能
网站前端开发基础知识学什么?Web前端开发网页制主要由HTML.CSS.JavaScript三大要素组成.随着企业需求变,前端开发技术的三要素也演变成现今的HTML5.CSS3.jQuery.响应式布 ...
- 每天学一点,一年有小成
@写在CSDN会员纪念日 每天学习一点点 做为一个写了20年的代码员,现在看来,我是成长的.进步的.1998年大学华业,同年用foxbase编写了第一个交付使用应用.要知道486时代,1.44M的一张 ...
- 题库来源:安全生产模拟考试一点通公众号小程序 电工(中级)模拟考试题根据新电工(中级)考试大纲要求,安全生产模拟考试一点通将电工(中级)模拟考试试题进行汇编,组成一套电工(中级)全真模拟考试试题,学
题库来源:安全生产模拟考试一点通公众号小程序 流动式起重机司机考试内容是安全生产模拟考试一点通生成的,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材汇编出流动式起重机司机仿真模拟考试. ...
- 小学生成语学习测试小程序【每天学一点成语】
有没有小学生成语学习小程序?有.小程序搜索"每天学一点成语",成语免费学习测试,成语答对了还可以赚红包. 小程序界面: 几万个成语学习在线测试,你的成语学习好帮手 小学生成语学习小 ...
- 日常养生小知识,赶紧学起来?
现在的人们每天忙于生活,忽略了自己的健康,等到疾病找到自己.才急忙去药店买药,去健身房锻炼,殊不知这个时候已经为时过晚!下面这些养生小知识,希望能给大家带来帮助! 少吃生冷刺激的食物,多吃蔬菜水果补充 ...
最新文章
- 第六章 非编码RNA鉴定
- 在线apt-get安装mysql_Linux Debain 通过apt-get 方式快速安装Mysql
- P3501-[POI2010]ANT-Antisymmetry【hash,二分答案】
- Cogs 376. [IOI2002]任务安排(后效性DP)
- NG客制项目下的I18n国际化标准方案
- 基于maven创建一个javaweb项目
- AttributeError: 'module' object has no attribute 'main'
- 字节流转换为对象的方法
- DataGridView
- 百度邮件曝光:高级技术总监接管CTO工作
- [PHP] 数据结构-二叉树的创建PHP实现
- php验证码图片看不清更换代码,php如何实现验证码看不清换一张的效果
- [Bzoj1597][Usaco2008 Mar]土地购买(斜率优化)
- oracle同一天,Oracle统计一个小时内,一天内、一个星期内、一个月内、一年内的数据...
- navicate:navicate.exe 无法找到入口
- 山东大学项目实训(三十二)—— 科室管理
- HTML的简要学习---超链接(待补充)
- 搭建普罗米修斯Prometheus监控系统
- python搜狗微信搜索wechatsogou 用法
- android12.0(S) 如何区分U盘和TF卡