1、某地区公共数据平台系统测试漏洞结果
漏洞名称 | 漏洞等级 |
暴力破解(验证码可绕)
|
中
|
CORS
资源共享跨域漏洞
|
中
|
存在
.DS_Store
文件泄露
| 低 |
2、漏洞定级依据
序号
|
漏洞等级
|
描述
|
1
|
紧急
|
可以直接被利用的漏洞,且利用难度较低。被攻击之后可能对网站
或服务器的正常运行造成严重影响,或对用户财产及个人信息造成
重大损失。
|
2 |
高危
|
被利用之后,造成的影响较大,但直接利用难度较高的漏洞。或本
身无法直接攻击,但能为进一步攻击造成极大便利的漏洞。
|
3 |
中危
|
利用难度极高,或满足严格条件才能实现攻击的漏洞。或漏洞本身
无法被直接攻击,但能为进一步攻击起较大帮助作用的漏洞。
|
4 |
低危
|
无法直接实现攻击,但提供的信息可能让攻击者更容易找到其他安
全漏洞。
|
3、【中危】暴力破解(验证码可绕)
(1)漏洞描述
由于没有对登录页面进行相关的人机验证机制,如无验证码、有验证码但可重复利用以
及无登录错误次数限制等
(2)漏洞危害
该漏洞导致攻击者可通过暴力破解可能获取用户登录账号和密码。
(3)测试截图:
验证码可绕过进行暴力破解,验证码并不在同一登录数据包校验
(4)解决方案:
1、将验证码验证业务从客户端 AJAX 改为服务端验证
原验证码验证方式:
// 验证验证码是否正确
var validateCode = $("#validateCode").val();
if(!validateCode){
$("#messageBox").removeClass("none");
$("#messageBox").text("验证码不可为空");
return;
}
//验证码客户端验证
submitData("${pageContext.request.contextPath}/servlet/validateCodeServlet",{validateCode:validateCode},function(data){
if(data) {
login();
} else {
$("#messageBox").removeClass("none");
$("#messageBox").text("验证码错误, 请重试.");
$('.validateCodeRefresh').click();
}
}, {}, 'get', false);
- 服务端生成二维码和唯一标识存入 Redis;
/**
* 验证码生成
* @param request
* @param response
* @throws IOException
*/
private void createImage(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0L);
response.setContentType("image/jpeg");
String width = request.getParameter("width");
String height = request.getParameter("height");
if (StringUtils.isNumeric(width) && StringUtils.isNumeric(height)) {
this.w = NumberUtils.toInt(width);
this.h = NumberUtils.toInt(height);
}
BufferedImage image = new BufferedImage(this.w, this.h, 1);
Graphics g = image.getGraphics();
this.createBackground(g);
Code character = this.createCharacter(g);
request.getSession().setAttribute(VALIDATE_CODE, character.getS());
g.dispose();
OutputStream out = response.getOutputStream();
ImageIO.write(image, "JPEG", out);
out.close();
//生成验证码唯一标识
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 20);
// //唯一标识传入Session
request.getSession().setAttribute(VALIDATE_UUID,uuid);
//唯一标识和验证码存入缓存
LoginNumTimes.storeVerificationCode(VALIDATE_UUID+uuid,character.getCode());
}
private Color getRandColor(int fc, int bc) {
int f = fc;
int b = bc;
Random random = new Random();
if (fc > 255) {
f = 255;
}
if (bc > 255) {
b = 255;
}
return new Color(f + random.nextInt(b - f), f + random.nextInt(b - f), f + random.nextInt(b - f));
}
private void createBackground(Graphics g) {
g.setColor(this.getRandColor(220, 250));
g.fillRect(0, 0, this.w, this.h);
for(int i = 0; i < 8; ++i) {
g.setColor(this.getRandColor(40, 150));
Random random = new Random();
int x = random.nextInt(this.w);
int y = random.nextInt(this.h);
int x1 = random.nextInt(this.w);
int y1 = random.nextInt(this.h);
g.drawLine(x, y, x1, y1);
}
}
private Code createCharacter(Graphics g) {
char[] codeSeq = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};
String[] fontTypes = new String[]{"Arial", "Arial Black", "AvantGarde Bk BT", "Calibri"};
Random random = new Random();
StringBuilder s = new StringBuilder();
String c = "";
for(int i = 0; i < 4; ++i) {
String r = String.valueOf(codeSeq[random.nextInt(codeSeq.length)]);
c = c+r;
g.setColor(new Color(50 + random.nextInt(100), 50 + random.nextInt(100), 50 + random.nextInt(100)));
g.setFont(new Font(fontTypes[random.nextInt(fontTypes.length)], 1, 26));
g.drawString(r, 15 * i + 5, 19 + random.nextInt(8));
s.append(r);
}
return new Code(s.toString(),c);
}
- 用户登录时再将 session 中 的唯一标识带回服务端从 Redis 中获取二维码进行比对;
//扫码登录
if(isCode){
if (credential instanceof RememberMeUsernamePasswordCredential){
//扫码登录标志
((RememberMeUsernamePasswordCredential) credential).setCode(true);
//扫码授权码
((RememberMeUsernamePasswordCredential) credential).setCode(code);
}
}else {
//服务端验证码验证
String uuid = (String) request.getSession().getAttribute(ValidateCodeServlet.VALIDATE_UUID);
String s = JedisUtils.get(ValidateCodeServlet.VALIDATE_UUID + uuid);
try {
if (s==null){
loginLogService.saveLog(request, username, new Exception("验证码已过期,请刷新后重新输入"), "用户登录失败:" + username);
Map<String, Class<? extends Exception>> handlerErrors = new HashMap<>();
handlerErrors.put("VerificationCodeExpiredException",VerificationCodeExpiredException.class);
throw new AuthenticationException(handlerErrors);
}
}catch (AuthenticationException e){
logger.error("AuthenticationViaFormAction.VerificationCodeExpiredException",e);
return newEvent(AUTHENTICATION_FAILURE, e);
}
try {
if (!s.equals(validateCode)){
loginLogService.saveLog(request, username, new Exception("验证码不正确,请重新输入"), "用户登录失败:" + username);
Map<String, Class<? extends Exception>> handlerErrors = new HashMap<>();
handlerErrors.put("VerificationCodeException",VerificationCodeException.class);
throw new AuthenticationException(handlerErrors);
}
}catch (AuthenticationException e){
logger.error("AuthenticationViaFormAction.VerificationCodeException",e);
return newEvent(AUTHENTICATION_FAILURE, e);
}
if (!StringUtils.hasText(username)) {
context.getFlowScope().put("AUTHENTICATION_FAILURE", "required.username");
loginLogService.saveLog(request, username, new Exception("登录用户名为空"), "用户登录失败,登录用户名为空");
return newEvent(AUTHENTICATION_FAILURE);
}
if (!StringUtils.hasText(password)) {
context.getFlowScope().put("AUTHENTICATION_FAILURE", "required.password");
loginLogService.saveLog(request, username, new Exception("登录密码为空"), "用户登录失败:" + username);
return newEvent(AUTHENTICATION_FAILURE);
}
}
- 所有业务 整合 security 安全框架,回显提示语和 sql 语句均编写在配置文件中,未在代码中体现。
/**
* @Author: 张佑威
* @Date: Created in 14:24 2022/7/4
* @Description: 身份验证异常处理程序
* @Modified By:
*/
public class AuthenticationExceptionHandler{
/** State name when no matching exception is found. */
private static final String UNKNOWN = "UNKNOWN";
/** Default message bundle prefix. */
private static final String DEFAULT_MESSAGE_BUNDLE_PREFIX = "authenticationFailure.";
/** Default list of errors this class knows how to handle. */
private static final List<Class<? extends Exception>> DEFAULT_ERROR_LIST =
new ArrayList<Class<? extends Exception>>();
private final Logger logger = LoggerFactory.getLogger(this.getClass());
static {
DEFAULT_ERROR_LIST.add(javax.security.auth.login.AccountLockedException.class);
DEFAULT_ERROR_LIST.add(javax.security.auth.login.FailedLoginException.class);
DEFAULT_ERROR_LIST.add(javax.security.auth.login.CredentialExpiredException.class);
DEFAULT_ERROR_LIST.add(javax.security.auth.login.AccountNotFoundException.class);
DEFAULT_ERROR_LIST.add(org.jasig.cas.authentication.AccountDisabledException.class);
DEFAULT_ERROR_LIST.add(org.jasig.cas.authentication.InvalidLoginLocationException.class);
DEFAULT_ERROR_LIST.add(org.jasig.cas.authentication.InvalidLoginTimeException.class);
DEFAULT_ERROR_LIST.add(DingUserUnboundException.class);
DEFAULT_ERROR_LIST.add(DingUserNotExistException.class);
DEFAULT_ERROR_LIST.add(VerificationCodeException.class);
DEFAULT_ERROR_LIST.add(VerificationCodeExpiredException.class);
DEFAULT_ERROR_LIST.add(TooManyAccountLoginsException.class);
DEFAULT_ERROR_LIST.add(TooManyIPRequestsException.class);
}
/** Ordered list of error classes that this class knows how to handle. */
@NotNull
private List<Class<? extends Exception>> errors = DEFAULT_ERROR_LIST;
/** String appended to exception class name to create a message bundle key for that particular error. */
private String messageBundlePrefix = DEFAULT_MESSAGE_BUNDLE_PREFIX;
/**
* Sets the list of errors that this class knows how to handle.
*
* @param errors List of errors in order of descending precedence.
*/
public void setErrors(final List<Class<? extends Exception>> errors) {
this.errors = errors;
}
public final List<Class<? extends Exception>> getErrors() {
return Collections.unmodifiableList(this.errors);
}
/**
* Sets the message bundle prefix appended to exception class names to create a message bundle key for that
* particular error.
*
* @param prefix Prefix appended to exception names.
*/
public void setMessageBundlePrefix(final String prefix) {
this.messageBundlePrefix = prefix;
}
/**
* Maps an authentication exception onto a state name equal to the simple class name of the
* {@link org.jasig.cas.authentication.AuthenticationException#getHandlerErrors()} with highest precedence.
* Also sets an ERROR severity message in the message context of the form
* <code>[messageBundlePrefix][exceptionClassSimpleName]</code> for each handler error that is
* configured. If not match is found, {@value #UNKNOWN} is returned.
*
* @param e Authentication error to handle.
*
* @return Name of next flow state to transition to or {@value #UNKNOWN}
*/
public String handle(final AuthenticationException e, final MessageContext messageContext) {
if (e != null) {
for (final Class<? extends Exception> kind : this.errors) {
for (final Class<? extends Exception> handlerError : e.getHandlerErrors().values()) {
if (handlerError != null && handlerError.equals(kind)) {
final String messageCode = this.messageBundlePrefix + handlerError.getSimpleName();
messageContext.addMessage(new MessageBuilder().error().code(messageCode).build());
return handlerError.getSimpleName();
}
}
}
}
final String messageCode = this.messageBundlePrefix + UNKNOWN;
logger.trace("Unable to translate handler errors of the authentication exception {}. Returning {} by default...", e, messageCode);
messageContext.addMessage(new MessageBuilder().error().code(messageCode).build());
return UNKNOWN;
}
- properties配置文件中添加回显信息异常统一读取
#Generic Success Screen Messages
screen.success.header=登录成功
screen.success.success=您已经成功登录中央认证系统。
screen.success.security=出于安全考虑,一旦您访问过那些需要您提供凭证信息的应用时,请操作完成之后关闭浏览器。
# Authentication failure messages
authenticationFailure.AccountDisabledException=账号不可用
authenticationFailure.AccountLockedException=账号输入错误次数过多,已被锁定
authenticationFailure.CredentialExpiredException=密码过期
#authenticationFailure.InvalidLoginLocationException=You cannot login from this workstation.
#authenticationFailure.InvalidLoginTimeException=Your account is forbidden to login at this time.
#authenticationFailure.AccountNotFoundException=该账号不存在,请先注册!
#authenticationFailure.AccountNotFoundException=该用户不存在,请先添加用户!
authenticationFailure.AccountNotFoundException=用户名或密码不正确,请重新输入!
#authenticationFailure.FailedLoginException=密码不正确,请重新输入!
authenticationFailure.FailedLoginException=用户名或密码不正确,请重新输入!
authenticationFailure.UNKNOWN=用户名和密码都不能为空!
authenticationFailure.VerificationCodeException=验证码错误,请重新输入!
authenticationFailure.VerificationCodeExpiredException=验证码过期,请刷新后重新输入!
authenticationFailure.TooManyAccountLoginsException=连续登录次数已达上限,请10分钟后再试!
authenticationFailure.TooManyIPRequestsException=当日IP请求次数已达上限,请1小时后再试!
authenticationFailure.DingUserNotExistException=未获取到浙政钉用户信息!
authenticationFailure.DingUserUnboundException=未查到相关用户信息,请联系管理员绑定浙政钉账号!
- 编写自定义异常类,整合security异常统一处理
异常名 | 作用场景 |
DingUserNotExistException | 浙政厅用户找不到异常 |
DingUserUnboundException | 浙政钉未绑定异常 |
TooManyAccountLoginsException | 连续登录次数已达上限 |
TooManyIPRequestsException | 当日IP请求次数已达上限 |
VerificationCodeException | 验证码错误,请重新输入! |
VerificationCodeExpiredException | 验证码过期,请刷新后重新输入! |
/**
* @Author: 张佑威
* @Date: Created in 14:24 2022/7/4
* @Description: 连续登录次数已达上限
* @Modified By:
*/
public class TooManyAccountLoginsException extends AccountException implements Serializable {
private static final long serialVersionUID = 1318370463436736729L;
/**
* Constructs a AccountException with no detail message. A detail
* message is a String that describes this particular exception.
*/
public TooManyAccountLoginsException() {
}
/**
* Constructs a AccountException with the specified detail message.
* A detail message is a String that describes this particular
* exception.
*
* <p>
*
* @param msg the detail message.
*/
public TooManyAccountLoginsException(String msg) {
super(msg);
}
}
2.针对恶意破解行为,加设业务逻辑:
同一用户 10 分钟内超 过 5 次重复登录或同一 IP 地址在 1 小时内重复登录请求 10 次则将该用户名或 IP 地址存入 Redis 中,锁定其对应时间。
//查询登录次数,校验是否超过阔值
Boolean loginKey = LoginNumTimes.getLoginKey(username);
try {
if (loginKey!=true){
loginLogService.saveLog(request, username, new Exception("连续登录次数已达上限,请10分钟后再试。"), "用户登录失败:" + username);
Map<String, Class<? extends Exception>> handlerErrors = new HashMap<>();
handlerErrors.put("TooManyAccountLoginsException",TooManyAccountLoginsException.class);
throw new AuthenticationException(handlerErrors);
}
}catch (AuthenticationException e){
logger.error("AuthenticationViaFormAction.TooManyAccountLoginsException",e);
return newEvent(AUTHENTICATION_FAILURE, e);
}
//获取请求IP
String ip = IpUtils.getIP(request);
Boolean ipKey = LoginNumTimes.getIPKey(ip);
try {
if (ipKey != true) {
loginLogService.saveLog(request, username, new Exception("当日IP请求次数已达上限,请24小时后再试。"), "用户登录失败:" + username);
Map<String, Class<? extends Exception>> handlerErrors = new HashMap<>();
handlerErrors.put("TooManyIPRequestsException",TooManyIPRequestsException.class);
throw new AuthenticationException(handlerErrors);
}
}catch (AuthenticationException e){
logger.error("AuthenticationViaFormAction.TooManyIPRequestsException",e);
return newEvent(AUTHENTICATION_FAILURE, e);
}
/**
* 1.验证码校验通过
* 2.账号锁定验证通过
* 3.IP锁定验证通过
*/
LoginNumTimes.setLoginNumTimes(username);
LoginNumTimes.setIPTimes(ip);
/**
* @Author: 张佑威
* @Date: Created in 14:24 2022/6/29
* @Description: 限制用户重复登录次数
* @Modified By:
*/
public class LoginNumTimes {
/**
* 登录时间间隔(秒)
*/
private static final int TIME_INTERVAL = 600;
/**
* 登录时间间隔(秒)
*/
private static final int TIME_IP = 1800;
/**
* 每10分钟内登录次数上限(次)
*/
private static final int FAILED_RETRY_TIMES = 5;
/**
* 同一IP当日请求次数上限(次)
*/
private static final int IP_RETRY_TIMES = 10;
/**
* 验证码失效时间(秒)
*/
private static final int VERIFICATIONCODE_RETRY_TIMES = 360;
/**
* redis记录用户登录次数key
*/
private static final String USER_LOGIN_FAILED_COUNT = "USER:LOGIN:FAILED:COUNT:";
/**
* redis记录IP请求次数key
*/
private static final String IP_LOGIN_FAILED_COUNT = "IP:LOGIN:FAILED:COUNT:";
/**
* 检验是否超出单日最大可登录次数
* @return
*/
public static Boolean getLoginKey(String username){
String key = USER_LOGIN_FAILED_COUNT + username;
String redisCounter = getRedisCounter(key);
if (Integer.parseInt(redisCounter)>=FAILED_RETRY_TIMES){
return false;
}else {
return true;
}
}
/**
* 检验是否超出单日最大可登录次数
* @return
*/
public static Boolean getIPKey(String ip){
String key = IP_LOGIN_FAILED_COUNT + ip;
String IpCounter = getRedisCounter(key);
if (Integer.parseInt(IpCounter)>=IP_RETRY_TIMES){
return false;
}else {
return true;
}
}
/**
* 根据key获取计数器
*
* @param key key
* @return
*/
private static String getRedisCounter(String key) {
return JedisUtils.get(key)==null?"0":JedisUtils.get(key);
}
/**
* 更新登录次数记录
* @param username
*/
public static void setLoginNumTimes(String username){
String key = USER_LOGIN_FAILED_COUNT + username;
String value = JedisUtils.get(key);
if (value!=null){
String newVlue = String.valueOf(Integer.parseInt(value)+1);
JedisUtils.set(key,newVlue,TIME_INTERVAL);
}else {
JedisUtils.set(key,"1",TIME_INTERVAL);
}
}
/**
* 更新IP请求次数记录
* @param ip
*/
public static void setIPTimes(String ip){
String key = IP_LOGIN_FAILED_COUNT + ip;
String IpCounter = getRedisCounter(key);
if (IpCounter!=null){
String newVlue = String.valueOf(Integer.parseInt(IpCounter)+1);
JedisUtils.set(key,newVlue,TIME_IP);
}else {
JedisUtils.set(key,"1",TIME_IP);
}
}
/**
* 存储验证码失效时间
* @param key
* @param VerificationCode
*/
public static void storeVerificationCode(String key,String VerificationCode){
JedisUtils.set(key,VerificationCode,VERIFICATIONCODE_RETRY_TIMES);
}
}
JedisUtils
public class JedisUtils {
public static Pool jedisPool = JedisApi.getPool();
public static Logger log = LoggerFactory.getLogger(JedisUtils.class);
/**
* 获取缓存
* @param key 键
* @return 值
*/
public static String get(String key) {
String value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
value = jedis.get(key);
value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;
log.debug("get {} = {}", key, value);
}
} catch (Exception e) {
log.warn("get {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 获取缓存
* @param key 键
* @return 值
*/
public static Object getObject(String key) {
Object value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
value = toObject(jedis.get(getBytesKey(key)));
log.debug("getObject {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getObject {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 设置缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static String set(String key, String value, int cacheSeconds) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.set(key, value);
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("set {} = {}", key, value);
} catch (Exception e) {
log.warn("set {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 设置缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static String setObject(String key, Object value, int cacheSeconds) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.set(getBytesKey(key), toBytes(value));
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setObject {} = {}", key, value);
} catch (Exception e) {
log.warn("setObject {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 获取List缓存
* @param key 键
* @return 值
*/
public static List<String> getList(String key) {
List<String> value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
value = jedis.lrange(key, 0, -1);
log.debug("getList {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getList {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 获取List缓存
* @param key 键
* @return 值
*/
public static List<Object> getObjectList(String key) {
List<Object> value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
List<byte[]> list = jedis.lrange(getBytesKey(key), 0, -1);
value = Lists.newArrayList();
for (byte[] bs : list){
value.add(toObject(bs));
}
log.debug("getObjectList {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getObjectList {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 设置List缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static long setList(String key, List<String> value, int cacheSeconds) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
jedis.del(key);
}
result = jedis.rpush(key, (String[])value.toArray());
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setList {} = {}", key, value);
} catch (Exception e) {
log.warn("setList {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 设置List缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static long setObjectList(String key, List<Object> value, int cacheSeconds) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
jedis.del(key);
}
List<byte[]> list = Lists.newArrayList();
for (Object o : value){
list.add(toBytes(o));
}
result = jedis.rpush(getBytesKey(key), (byte[][])list.toArray());
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setObjectList {} = {}", key, value);
} catch (Exception e) {
log.warn("setObjectList {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 向List缓存中添加值
* @param key 键
* @param value 值
* @return
*/
public static long listAdd(String key, String... value) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.rpush(key, value);
log.debug("listAdd {} = {}", key, value);
} catch (Exception e) {
log.warn("listAdd {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 向List缓存中添加值
* @param key 键
* @param value 值
* @return
*/
public static long listObjectAdd(String key, Object... value) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
List<byte[]> list = Lists.newArrayList();
for (Object o : value){
list.add(toBytes(o));
}
result = jedis.rpush(getBytesKey(key), (byte[][])list.toArray());
log.debug("listObjectAdd {} = {}", key, value);
} catch (Exception e) {
log.warn("listObjectAdd {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 获取缓存
* @param key 键
* @return 值
*/
public static Set<String> getSet(String key) {
Set<String> value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
value = jedis.smembers(key);
log.debug("getSet {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getSet {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 获取缓存
* @param key 键
* @return 值
*/
public static Set<Object> getObjectSet(String key) {
Set<Object> value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
value = Sets.newHashSet();
Set<byte[]> set = jedis.smembers(getBytesKey(key));
for (byte[] bs : set){
value.add(toObject(bs));
}
log.debug("getObjectSet {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getObjectSet {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 设置Set缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static long setSet(String key, Set<String> value, int cacheSeconds) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
jedis.del(key);
}
result = jedis.sadd(key, (String[])value.toArray());
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setSet {} = {}", key, value);
} catch (Exception e) {
log.warn("setSet {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 设置Set缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static long setObjectSet(String key, Set<Object> value, int cacheSeconds) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
jedis.del(key);
}
Set<byte[]> set = Sets.newHashSet();
for (Object o : value){
set.add(toBytes(o));
}
result = jedis.sadd(getBytesKey(key), (byte[][])set.toArray());
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setObjectSet {} = {}", key, value);
} catch (Exception e) {
log.warn("setObjectSet {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 向Set缓存中添加值
* @param key 键
* @param value 值
* @return
*/
public static long setSetAdd(String key, String... value) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.sadd(key, value);
log.debug("setSetAdd {} = {}", key, value);
} catch (Exception e) {
log.warn("setSetAdd {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 向Set缓存中添加值
* @param key 键
* @param value 值
* @return
*/
public static long setSetObjectAdd(String key, Object... value) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
Set<byte[]> set = Sets.newHashSet();
for (Object o : value){
set.add(toBytes(o));
}
result = jedis.rpush(getBytesKey(key), (byte[][])set.toArray());
log.debug("setSetObjectAdd {} = {}", key, value);
} catch (Exception e) {
log.warn("setSetObjectAdd {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 获取Map缓存
* @param key 键
* @return 值
*/
public static Map<String, String> getMap(String key) {
Map<String, String> value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
value = jedis.hgetAll(key);
log.debug("getMap {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getMap {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 获取Map缓存
* @param key 键
* @return 值
*/
public static Map<String, Object> getObjectMap(String key) {
Map<String, Object> value = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
value = Maps.newHashMap();
Map<byte[], byte[]> map = jedis.hgetAll(getBytesKey(key));
for (Map.Entry<byte[], byte[]> e : map.entrySet()){
value.put(StringUtils.toString(e.getKey()), toObject(e.getValue()));
}
log.debug("getObjectMap {} = {}", key, value);
}
} catch (Exception e) {
log.warn("getObjectMap {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return value;
}
/**
* 设置Map缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static String setMap(String key, Map<String, String> value, int cacheSeconds) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)) {
jedis.del(key);
}
result = jedis.hmset(key, value);
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setMap {} = {}", key, value);
} catch (Exception e) {
log.warn("setMap {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 设置Map缓存
* @param key 键
* @param value 值
* @param cacheSeconds 超时时间,0为不超时
* @return
*/
public static String setObjectMap(String key, Map<String, Object> value, int cacheSeconds) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))) {
jedis.del(key);
}
Map<byte[], byte[]> map = Maps.newHashMap();
for (Map.Entry<String, Object> e : value.entrySet()){
map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));
}
result = jedis.hmset(getBytesKey(key), (Map<byte[], byte[]>)map);
if (cacheSeconds != 0) {
jedis.expire(key, cacheSeconds);
}
log.debug("setObjectMap {} = {}", key, value);
} catch (Exception e) {
log.warn("setObjectMap {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 向Map缓存中添加值
* @param key 键
* @param value 值
* @return
*/
public static String mapPut(String key, Map<String, String> value) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.hmset(key, value);
log.debug("mapPut {} = {}", key, value);
} catch (Exception e) {
log.warn("mapPut {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 向Map缓存中添加值
* @param key 键
* @param value 值
* @return
*/
public static String mapObjectPut(String key, Map<String, Object> value) {
String result = null;
Jedis jedis = null;
try {
jedis = getResource();
Map<byte[], byte[]> map = Maps.newHashMap();
for (Map.Entry<String, Object> e : value.entrySet()){
map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));
}
result = jedis.hmset(getBytesKey(key), (Map<byte[], byte[]>)map);
log.debug("mapObjectPut {} = {}", key, value);
} catch (Exception e) {
log.warn("mapObjectPut {} = {}", key, value, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 移除Map缓存中的值
* @param key 键
* @param mapKey 值
* @return
*/
public static long mapRemove(String key, String mapKey) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.hdel(key, mapKey);
log.debug("mapRemove {} {}", key, mapKey);
} catch (Exception e) {
log.warn("mapRemove {} {}", key, mapKey, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 移除Map缓存中的值
* @param key 键
* @param mapKey 值
* @return
*/
public static long mapObjectRemove(String key, String mapKey) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.hdel(getBytesKey(key), getBytesKey(mapKey));
log.debug("mapObjectRemove {} {}", key, mapKey);
} catch (Exception e) {
log.warn("mapObjectRemove {} {}", key, mapKey, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 判断Map缓存中的Key是否存在
* @param key 键
* @param mapKey 值
* @return
*/
public static boolean mapExists(String key, String mapKey) {
boolean result = false;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.hexists(key, mapKey);
log.debug("mapExists {} {}", key, mapKey);
} catch (Exception e) {
log.warn("mapExists {} {}", key, mapKey, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 判断Map缓存中的Key是否存在
* @param key 键
* @param mapKey 值
* @return
*/
public static boolean mapObjectExists(String key, String mapKey) {
boolean result = false;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.hexists(getBytesKey(key), getBytesKey(mapKey));
log.debug("mapObjectExists {} {}", key, mapKey);
} catch (Exception e) {
log.warn("mapObjectExists {} {}", key, mapKey, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 删除缓存
* @param key 键
* @return
*/
public static long del(String key) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(key)){
result = jedis.del(key);
log.debug("del {}", key);
}else{
log.debug("del {} not exists", key);
}
} catch (Exception e) {
log.warn("del {}", key, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 删除缓存
* @param key 键
* @return
*/
public static long delObject(String key) {
long result = 0;
Jedis jedis = null;
try {
jedis = getResource();
if (jedis.exists(getBytesKey(key))){
result = jedis.del(getBytesKey(key));
log.debug("delObject {}", key);
}else{
log.debug("delObject {} not exists", key);
}
} catch (Exception e) {
log.warn("delObject {}", key, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 缓存是否存在
* @param key 键
* @return
*/
public static boolean exists(String key) {
boolean result = false;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.exists(key);
log.debug("exists {}", key);
} catch (Exception e) {
log.warn("exists {}", key, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 缓存是否存在
* @param key 键
* @return
*/
public static boolean existsObject(String key) {
boolean result = false;
Jedis jedis = null;
try {
jedis = getResource();
result = jedis.exists(getBytesKey(key));
log.debug("existsObject {}", key);
} catch (Exception e) {
log.warn("existsObject {}", key, e);
} finally {
returnResource(jedis);
}
return result;
}
/**
* 获取资源
* @return
* @throws JedisException
*/
public static Jedis getResource() throws JedisException {
Jedis jedis = null;
try {
jedis = (Jedis) jedisPool.getResource();
// log.debug("getResource.", jedis);
} catch (JedisException e) {
log.warn("getResource.", e);
returnBrokenResource(jedis);
throw e;
}
return jedis;
}
/**
* 归还资源
* @param jedis
*/
public static void returnBrokenResource(Jedis jedis) {
if (jedis != null) {
jedisPool.returnBrokenResource(jedis);
}
}
/**
* 释放资源
* @param jedis
*/
public static void returnResource(Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
/**
* 获取byte[]类型Key
* @param object
* @return
*/
public static byte[] getBytesKey(Object object){
if(object instanceof String){
return StringUtils.getBytes((String)object);
}else{
return ObjectUtils.serialize(object);
}
}
/**
* Object转换byte[]类型
* @param object
* @return
*/
public static byte[] toBytes(Object object){
return ObjectUtils.serialize(object);
}
/**
* byte[]型转换Object
* @param bytes
* @return
*/
public static Object toObject(byte[] bytes){
return ObjectUtils.unserialize(bytes);
}
}
4、【中危】CORS 资源共享跨域漏洞
(1)漏洞描述
跨域资源共享
(CORS)
是一种放宽同源策略的机制,它允许浏览器向跨源服务器,发出
XMLHttpRequest
请求,从而克服了
AJAX
只能同源使用的限制,以使不同的网站可以跨
域获取数据,跨域资源共享
CORS
漏洞主要是由于程序员配置不当,对于
Origin
源校验
不严格,从而造成跨域问题。
(2)漏洞危害
攻击者可以利用
CORS
错误配置漏洞,从恶意网站跨域读取受害网站的敏感信息。
(3)测试截图
Origin
可以任意调整
(4)加固方法
- 1、禁止配置 “Access-Control-Allow-Origin” 为 “
- *” 和 “null”;
- 2、严格校验 “Origin” 值,避免出现权限泄露;
- 3、避免使用 “Access-Control-Allow-Credentials:true”;
- 4、减少 “Access-Control-Allow-Methods” 所允许的方法;
5、【低危】存在.DS_Store 文件泄露
(1)漏洞描述
.DS_Store
是
Mac
下
Finder
用来保存如何展示 文件
/
文件夹 的数据文件,每个文件夹
下对应一个。
(2)漏洞危害
由于开发/设计人员在发布代码时未删除文件夹中隐藏的.DS_store,可能造成文件目录
结构泄漏、源代码文件等敏感信息的泄露。
(3)测试截图
通过该文件可以获取部分网站结构、文件信息
(4)解决方法
进入该项目部署Linux环境,通过查看nginx配置信息,找到项目根目录
使用模糊查找命令和删除命令删除所有.DS_Store 文件