🔒 xss 过滤
This commit is contained in:
parent
d05db15b32
commit
ac247f8e68
@ -12,10 +12,7 @@ import com.rymcu.forest.mapper.ArticleMapper;
|
|||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.TagService;
|
import com.rymcu.forest.service.TagService;
|
||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.Html2TextUtil;
|
import com.rymcu.forest.util.*;
|
||||||
import com.rymcu.forest.util.NotificationUtils;
|
|
||||||
import com.rymcu.forest.util.UserUtils;
|
|
||||||
import com.rymcu.forest.util.Utils;
|
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
import com.rymcu.forest.web.api.exception.ErrorCode;
|
import com.rymcu.forest.web.api.exception.ErrorCode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -112,7 +109,7 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
String articleTitle = article.getArticleTitle();
|
String articleTitle = article.getArticleTitle();
|
||||||
String articleTags = article.getArticleTags();
|
String articleTags = article.getArticleTags();
|
||||||
String articleContent = article.getArticleContent();
|
String articleContent = article.getArticleContent();
|
||||||
String articleContentHtml = article.getArticleContentHtml();
|
String articleContentHtml = XssUtils.replaceHtmlCode(article.getArticleContentHtml());
|
||||||
User user = UserUtils.getCurrentUserByToken();
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
if (Objects.isNull(user)) {
|
if (Objects.isNull(user)) {
|
||||||
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
|
throw new BaseApiException(ErrorCode.INVALID_TOKEN);
|
||||||
@ -358,7 +355,7 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
if (!type.equals(articleList)) {
|
if (!type.equals(articleList)) {
|
||||||
ArticleContent articleContent = articleMapper.selectArticleContent(article.getIdArticle());
|
ArticleContent articleContent = articleMapper.selectArticleContent(article.getIdArticle());
|
||||||
if (type.equals(articleView)) {
|
if (type.equals(articleView)) {
|
||||||
article.setArticleContent(articleContent.getArticleContentHtml());
|
article.setArticleContent(XssUtils.replaceHtmlCode(articleContent.getArticleContentHtml()));
|
||||||
// 获取所属作品集列表数据
|
// 获取所属作品集列表数据
|
||||||
List<PortfolioArticleDTO> portfolioArticleDTOList = articleMapper.selectPortfolioArticles(article.getIdArticle());
|
List<PortfolioArticleDTO> portfolioArticleDTOList = articleMapper.selectPortfolioArticles(article.getIdArticle());
|
||||||
portfolioArticleDTOList.forEach(this::genPortfolioArticles);
|
portfolioArticleDTOList.forEach(this::genPortfolioArticles);
|
||||||
@ -366,7 +363,7 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
} else if (type.equals(articleEdit)) {
|
} else if (type.equals(articleEdit)) {
|
||||||
article.setArticleContent(articleContent.getArticleContent());
|
article.setArticleContent(articleContent.getArticleContent());
|
||||||
} else {
|
} else {
|
||||||
article.setArticleContent(articleContent.getArticleContentHtml());
|
article.setArticleContent(XssUtils.replaceHtmlCode(articleContent.getArticleContentHtml()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return article;
|
return article;
|
||||||
|
@ -12,6 +12,7 @@ import com.rymcu.forest.service.CommentService;
|
|||||||
import com.rymcu.forest.util.Html2TextUtil;
|
import com.rymcu.forest.util.Html2TextUtil;
|
||||||
import com.rymcu.forest.util.NotificationUtils;
|
import com.rymcu.forest.util.NotificationUtils;
|
||||||
import com.rymcu.forest.util.Utils;
|
import com.rymcu.forest.util.Utils;
|
||||||
|
import com.rymcu.forest.util.XssUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@ -42,6 +43,7 @@ public class CommentServiceImpl extends AbstractService<Comment> implements Comm
|
|||||||
private List<CommentDTO> genComments(List<CommentDTO> commentDTOList) {
|
private List<CommentDTO> genComments(List<CommentDTO> commentDTOList) {
|
||||||
commentDTOList.forEach(commentDTO -> {
|
commentDTOList.forEach(commentDTO -> {
|
||||||
commentDTO.setTimeAgo(Utils.getTimeAgo(commentDTO.getCreatedTime()));
|
commentDTO.setTimeAgo(Utils.getTimeAgo(commentDTO.getCreatedTime()));
|
||||||
|
commentDTO.setCommentContent(XssUtils.replaceHtmlCode(commentDTO.getCommentContent()));
|
||||||
if (commentDTO.getCommentAuthorId() != null) {
|
if (commentDTO.getCommentAuthorId() != null) {
|
||||||
Author author = commentMapper.selectAuthor(commentDTO.getCommentAuthorId());
|
Author author = commentMapper.selectAuthor(commentDTO.getCommentAuthorId());
|
||||||
if (author != null) {
|
if (author != null) {
|
||||||
@ -87,10 +89,10 @@ public class CommentServiceImpl extends AbstractService<Comment> implements Comm
|
|||||||
comment.setCommentIP(ip);
|
comment.setCommentIP(ip);
|
||||||
comment.setCommentUA(ua);
|
comment.setCommentUA(ua);
|
||||||
comment.setCreatedTime(new Date());
|
comment.setCreatedTime(new Date());
|
||||||
|
comment.setCommentContent(XssUtils.replaceHtmlCode(comment.getCommentContent()));
|
||||||
commentMapper.insertSelective(comment);
|
commentMapper.insertSelective(comment);
|
||||||
StringBuilder commentSharpUrl = new StringBuilder(article.getArticlePermalink());
|
String commentSharpUrl = article.getArticlePermalink() + "#comment-" + comment.getIdComment();
|
||||||
commentSharpUrl.append("#comment-").append(comment.getIdComment());
|
commentMapper.updateCommentSharpUrl(comment.getIdComment(), commentSharpUrl);
|
||||||
commentMapper.updateCommentSharpUrl(comment.getIdComment(), commentSharpUrl.toString());
|
|
||||||
|
|
||||||
String commentContent = comment.getCommentContent();
|
String commentContent = comment.getCommentContent();
|
||||||
if(StringUtils.isNotBlank(commentContent)){
|
if(StringUtils.isNotBlank(commentContent)){
|
||||||
|
@ -15,6 +15,7 @@ import com.rymcu.forest.service.PortfolioService;
|
|||||||
import com.rymcu.forest.service.UserService;
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import com.rymcu.forest.util.Utils;
|
import com.rymcu.forest.util.Utils;
|
||||||
|
import com.rymcu.forest.util.XssUtils;
|
||||||
import com.rymcu.forest.web.api.common.UploadController;
|
import com.rymcu.forest.web.api.common.UploadController;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@ -75,6 +76,7 @@ public class PortfolioServiceImpl extends AbstractService<Portfolio> implements
|
|||||||
portfolio.setPortfolioAuthorId(user.getIdUser());
|
portfolio.setPortfolioAuthorId(user.getIdUser());
|
||||||
portfolio.setCreatedTime(new Date());
|
portfolio.setCreatedTime(new Date());
|
||||||
portfolio.setUpdatedTime(portfolio.getCreatedTime());
|
portfolio.setUpdatedTime(portfolio.getCreatedTime());
|
||||||
|
portfolio.setPortfolioDescriptionHtml(XssUtils.replaceHtmlCode(portfolio.getPortfolioDescription()));
|
||||||
portfolioMapper.insertSelective(portfolio);
|
portfolioMapper.insertSelective(portfolio);
|
||||||
PortfolioIndexUtil.addIndex(
|
PortfolioIndexUtil.addIndex(
|
||||||
PortfolioLucene.builder()
|
PortfolioLucene.builder()
|
||||||
|
@ -13,6 +13,7 @@ import com.rymcu.forest.service.TagService;
|
|||||||
import com.rymcu.forest.util.BaiDuAipUtils;
|
import com.rymcu.forest.util.BaiDuAipUtils;
|
||||||
import com.rymcu.forest.util.CacheUtils;
|
import com.rymcu.forest.util.CacheUtils;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.util.XssUtils;
|
||||||
import com.rymcu.forest.web.api.common.UploadController;
|
import com.rymcu.forest.web.api.common.UploadController;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@ -127,6 +128,7 @@ public class TagServiceImpl extends AbstractService<Tag> implements TagService {
|
|||||||
Integer result;
|
Integer result;
|
||||||
|
|
||||||
Map map = new HashMap(1);
|
Map map = new HashMap(1);
|
||||||
|
tag.setTagDescription(XssUtils.replaceHtmlCode(tag.getTagDescription()));
|
||||||
if (tag.getIdTag() == null) {
|
if (tag.getIdTag() == null) {
|
||||||
if (StringUtils.isBlank(tag.getTagTitle())) {
|
if (StringUtils.isBlank(tag.getTagTitle())) {
|
||||||
map.put("message", "标签名不能为空!");
|
map.put("message", "标签名不能为空!");
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.http.HtmlUtil;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.rymcu.forest.core.service.AbstractService;
|
import com.rymcu.forest.core.service.AbstractService;
|
||||||
@ -10,6 +11,7 @@ import com.rymcu.forest.entity.Tag;
|
|||||||
import com.rymcu.forest.entity.Topic;
|
import com.rymcu.forest.entity.Topic;
|
||||||
import com.rymcu.forest.mapper.TopicMapper;
|
import com.rymcu.forest.mapper.TopicMapper;
|
||||||
import com.rymcu.forest.service.TopicService;
|
import com.rymcu.forest.service.TopicService;
|
||||||
|
import com.rymcu.forest.util.XssUtils;
|
||||||
import com.rymcu.forest.web.api.common.UploadController;
|
import com.rymcu.forest.web.api.common.UploadController;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -48,6 +50,7 @@ public class TopicServiceImpl extends AbstractService<Topic> implements TopicSer
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Map saveTopic(Topic topic) {
|
public Map saveTopic(Topic topic) {
|
||||||
Integer result = 0;
|
Integer result = 0;
|
||||||
|
topic.setTopicDescriptionHtml(XssUtils.replaceHtmlCode(topic.getTopicDescriptionHtml()));
|
||||||
Map map = new HashMap(1);
|
Map map = new HashMap(1);
|
||||||
if (topic.getIdTopic() == null) {
|
if (topic.getIdTopic() == null) {
|
||||||
if (StringUtils.isBlank(topic.getTopicTitle())) {
|
if (StringUtils.isBlank(topic.getTopicTitle())) {
|
||||||
|
110
src/main/java/com/rymcu/forest/util/XssUtils.java
Normal file
110
src/main/java/com/rymcu/forest/util/XssUtils.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package com.rymcu.forest.util;
|
||||||
|
|
||||||
|
import cn.hutool.http.HtmlUtil;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2022/5/10 17:06.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @packageName com.rymcu.forest.util
|
||||||
|
*/
|
||||||
|
public class XssUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滤除content中的危险 HTML 代码, 主要是脚本代码, 滚动字幕代码以及脚本事件处理代码
|
||||||
|
* @param content 需要滤除的字符串
|
||||||
|
* @return 过滤的结果
|
||||||
|
*/
|
||||||
|
public static String replaceHtmlCode(String content) {
|
||||||
|
if (StringUtils.isBlank(content)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (0 == content.length()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// 需要滤除的脚本事件关键字
|
||||||
|
String[] eventKeywords = {
|
||||||
|
"onmouseover", "onmouseout", "onmousedown", "onmouseup", "onmousemove", "onclick", "ondblclick",
|
||||||
|
"onkeypress", "onkeydown", "onkeyup", "ondragstart", "onerrorupdate", "onhelp", "onreadystatechange",
|
||||||
|
"onrowenter", "onrowexit", "onselectstart", "onload", "onunload", "onbeforeunload", "onblur",
|
||||||
|
"onerror", "onfocus", "onresize", "onscroll", "oncontextmenu", "alert"
|
||||||
|
};
|
||||||
|
// content = replace(content, "<script", "<script", false);
|
||||||
|
// content = replace(content, "</script", "</script", false);
|
||||||
|
// content = replace(content, "<marquee", "<marquee", false);
|
||||||
|
// content = replace(content, "</marquee", "</marquee", false);
|
||||||
|
content = HtmlUtil.removeHtmlTag(content, "script");
|
||||||
|
content = HtmlUtil.removeHtmlTag(content, "marquee");
|
||||||
|
// 将单引号替换成下划线
|
||||||
|
// content = replace(content, "'", "_", false);
|
||||||
|
// 将双引号替换成下划线
|
||||||
|
// content = replace(content, "\"", "_", false);
|
||||||
|
// 滤除脚本事件代码
|
||||||
|
for (int i = 0; i < eventKeywords.length; i++) {
|
||||||
|
// 去除相关属性
|
||||||
|
content = HtmlUtil.removeHtmlAttr(content, eventKeywords[i]);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串 source 中的 oldStr 替换为 newStr, 并以大小写敏感方式进行查找
|
||||||
|
*
|
||||||
|
* @param source 需要替换的源字符串
|
||||||
|
* @param oldStr 需要被替换的老字符串
|
||||||
|
* @param newStr 替换为的新字符串
|
||||||
|
*/
|
||||||
|
private static String replace(String source, String oldStr, String newStr) {
|
||||||
|
return replace(source, oldStr, newStr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串 source 中的 oldStr 替换为 newStr, matchCase 为是否设置大小写敏感查找
|
||||||
|
*
|
||||||
|
* @param source 需要替换的源字符串
|
||||||
|
* @param oldStr 需要被替换的老字符串
|
||||||
|
* @param newStr 替换为的新字符串
|
||||||
|
* @param matchCase 是否需要按照大小写敏感方式查找
|
||||||
|
*/
|
||||||
|
private static String replace(String source, String oldStr, String newStr,boolean matchCase) {
|
||||||
|
if (StringUtils.isBlank(source)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 首先检查旧字符串是否存在, 不存在就不进行替换
|
||||||
|
if (!source.toLowerCase().contains(oldStr.toLowerCase())) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
int findStartPos = 0;
|
||||||
|
int a = 0;
|
||||||
|
while (a > -1) {
|
||||||
|
int b = 0;
|
||||||
|
String str1, str2, str3, str4, strA, strB;
|
||||||
|
str1 = source;
|
||||||
|
str2 = str1.toLowerCase();
|
||||||
|
str3 = oldStr;
|
||||||
|
str4 = str3.toLowerCase();
|
||||||
|
if (matchCase) {
|
||||||
|
strA = str1;
|
||||||
|
strB = str3;
|
||||||
|
} else {
|
||||||
|
strA = str2;
|
||||||
|
strB = str4;
|
||||||
|
}
|
||||||
|
a = strA.indexOf(strB, findStartPos);
|
||||||
|
if (a > -1) {
|
||||||
|
b = oldStr.length();
|
||||||
|
findStartPos = a + b;
|
||||||
|
StringBuilder stringBuilder = new StringBuilder(source);
|
||||||
|
source = stringBuilder.replace(a, a + b, newStr) + "";
|
||||||
|
// 新的查找开始点位于替换后的字符串的结尾
|
||||||
|
findStartPos = findStartPos + newStr.length() - b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user