目录简介

在字符串标准化之后进行校验

注意不可信字符串的格式化

小心使用Runtime.exec()

正则表达式的匹配

简介

为了保证java程序的安全,任何外部用户的输入我们都认为是可能有恶意攻击意图,我们需要对所有的用户输入都进行一定程度的校验。

本文将带领大家探讨一下用户输入校验的一些场景。一起来看看吧。

在字符串标准化之后进行校验

通常我们在进行字符串校验的时候需要对一些特殊字符进行过滤,过滤之后再进行字符串的校验。

我们知道在java中字符是基于Unicode进行编码的。但是在Unicode中,同一个字符可能有不同的表示形式。所以我们需要对字符进行标准化。

java中有一个专门的类Normalizer来负责处理,字符标准化的问题。

我们看下面一个例子:

public void testNormalizer(){

System.out.println(Normalizer.normalize("\u00C1", Normalizer.Form.NFKC));

System.out.println(Normalizer.normalize("\u0041\u0301", Normalizer.Form.NFKC));

}

输出结果:

Á

Á

我们可以看到,虽然两者的Unicode不一样,但是最终表示的字符是一样的。所以我们在进行字符验证的时候,一定要先进行normalize处理。

考虑下面的例子:

public void falseNormalize(){

String s = "\uFE64" + "script" + "\uFE65";

Pattern pattern = Pattern.compile("[<>]"); // 检查是否有尖括号

Matcher matcher = pattern.matcher(s);

if (matcher.find()) {

throw new IllegalStateException();

}

s = Normalizer.normalize(s, Normalizer.Form.NFKC);

}

其中\uFE64表示的是,程序的本意是判断输入的字符串是否包含了尖括号,但是因为直接传入的是unicode字符,所以直接compile是检测不到的。

我们需要对代码进行下面的改动:

public void trueNormalize(){

String s = "\uFE64" + "script" + "\uFE65";

s = Normalizer.normalize(s, Normalizer.Form.NFKC);

Pattern pattern = Pattern.compile("[<>]"); // 检查是否有尖括号

Matcher matcher = pattern.matcher(s);

if (matcher.find()) {

throw new IllegalStateException();

}

}

先进行normalize操作,然后再进行字符验证。

注意不可信字符串的格式化

我们经常会使用到格式化来对字符串进行格式化,在格式化的时候如果格式化字符串里面带有用户输入信息,那么我们就要注意了。

看下面的例子:

public void wrongFormat(){

Calendar c = new GregorianCalendar(2020, GregorianCalendar.JULY, 27);

String input=" %1$tm";

System.out.format(input + " 时间不匹配,应该是某个月的第 %1$terd 天", c);

}

粗看一下没什么问题,但是我们的input中包含了格式化信息,最后输出结果:

07 时间不匹配,应该是某个月的第 27rd 天

变相的,我们获取到了系统内部的信息,在某些情况下面,可能会暴露系统的内部逻辑。

上面的例子我们应该将input也作为一个参数,如下所示:

public void rightFormat(){

Calendar c = new GregorianCalendar(2020, GregorianCalendar.JULY, 27);

String input=" %1$tm";

System.out.format("%s 时间不匹配,应该是某个月的第 %terd 天",input, c);

}

输出结果:

%1$tm 时间不匹配,应该是某个月的第 27rd 天

小心使用Runtime.exec()

我们知道Runtime.exec()使用来调用系统命令的,如果有恶意的用户调用了“rm -rf /”,一切的一切都完蛋了。

所以,我们在调用Runtime.exec()的时候,一定要小心注意检测用户的输入。

看下面的一个例子:

public void wrongExec() throws IOException {

String dir = System.getProperty("dir");

Runtime rt = Runtime.getRuntime();

Process proc = rt.exec(new String[] {"sh", "-c", "ls " + dir});

}

上面的例子中,我们从系统属性中读取dir,然后执行了系统的ls命令来查看dir中的内容。

如果有恶意用户给dir赋值成:

/usr & rm -rf /

那么系统实际上执行的命令就是:

sh -c 'ls /usr & rm -rf /'

从而导致恶意的删除。

解决上面的问题也有几个方法,第一个方法就是对输入做个校验,比如我们只运行dir包含特定的字符:

public void correctExec1() throws IOException {

String dir = System.getProperty("dir");

if (!Pattern.matches("[0-9A-Za-z@.]+", dir)) {

// Handle error

}

Runtime rt = Runtime.getRuntime();

Process proc = rt.exec(new String[] {"sh", "-c", "ls " + dir});

}

第二种方法就是使用switch语句,限定特定的输入:

public void correctExec2(){

String dir = System.getProperty("dir");

switch (dir){

case "/usr":

System.out.println("/usr");

break;

case "/local":

System.out.println("/local");

break;

default:

break;

}

}

还有一种就是不使用Runtime.exec()方法,而是使用java自带的方法。

正则表达式的匹配

在正则表达式的构建过程中,如果使用用户自定义输入,同样的也需要进行输入校验。

考虑下面的正则表达式:

(.*? +public\[\d+\] +.*.*)

上面的表达式本意是想在public[1234]这样的日志信息中,搜索用户的输入。

但是用户实际上可以输入下面的信息:

.*)|(.*

最终导致正则表达式变成下面的样子:

(.*? +public\[\d+\] +.*.*)|(.*.*)

从而导致匹配所有的日志信息。

解决方法也有两个,一个是使用白名单,判断用户的输入。一个是使用Pattern.quote()来对恶意字符进行转义。

本文的代码:

learn-java-base-9-to-20/tree/master/security

本文已收录于 http://www.flydean.com/java-security-code-line-input/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

java判断输入的格式化_java安全编码指南之:输入校验 - flydean - 博客园相关推荐

  1. java密码安全验证_java安全编码指南之:输入校验

    简介 为了保证java程序的安全,任何外部用户的输入我们都认为是可能有恶意攻击意图,我们需要对所有的用户输入都进行一定程度的校验. 本文将带领大家探讨一下用户输入校验的一些场景.一起来看看吧. 在字符 ...

  2. java声明代码是什么_java安全编码指南之:声明和初始化说明

    简介 在java对象和字段的初始化过程中会遇到哪些安全性问题呢?一起来看看吧. 初始化顺序 根据JLS(Java Language Specification)中的定义,class在初始化过程中,需要 ...

  3. Java实现 第三方的验证码发送问题--博客园老牛大讲堂

    简要:本篇文章,主要介绍怎样利用第三方平台实现短信验证码的发送问题.--博客园老牛大讲堂 1.Java发送(验证码,短信)原理--博客园老牛大讲堂 1.首先用户选定一个第三方平台. 2.进行一系列操作 ...

  4. try catch对异常进行输出到日志、_java安全编码指南之:异常处理

    点击上方的蓝字关注我吧 程序那些事 简介 异常是java程序员无法避免的一个话题,我们会有JVM自己的异常也有应用程序的异常,对于不同的异常,我们的处理原则是不是一样的呢? 一起来看看吧. 异常简介 ...

  5. java输出当前时间_JAVA中获取当前系统时间 - Matrix54 - 博客园

    JAVA中获取当前系统时间 - Matrix54 - 博客园 一. 获取当前系统时间和日期并格式化输出: import java.util.Date; import java.text.SimpleD ...

  6. java list 博客园_Java集合系列(一)List集合

    List的几种实现的区别与联系 List主要有ArrayList.LinkedList与Vector几种实现. ArrayList底层数据结构是数组, 增删慢.查询快; 线程不安全, 效率高; 不可以 ...

  7. Java集合和泛型练习及面试题——博客园:师妹开讲啦

    给定一段JAVA代码如下:要打印出list中存储的内容,以下语句正确的是( B  ) ArrayList list = new ArrayList( ) list.add("a") ...

  8. 回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议 - 左潇龙 - 博客园...

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  9. java 使用webmagic 爬虫框架爬取博客园数据

    java 使用webmagic 爬虫框架爬取博客园数据存入数据库 学习记录   webmagic简介: WebMagic是一个简单灵活的Java爬虫框架.你可以快速开发出一个高效.易维护的爬虫. ht ...

最新文章

  1. String insert()总结
  2. php7的foreach遍历数组,PHP中使用foreach遍历三维数组
  3. Qt中使用线程的几种方式及区别
  4. 大数据在医疗保健中的真正愿景
  5. 《信息存储与管理》读书笔记7 存储虚拟化
  6. [html] 本地存储和cookie之间的区别是什么?
  7. QLive EULA
  8. linux挂载win下的共享文件
  9. Win7+Ubuntu双系统时间不一致
  10. apache启动失败查看错误信息
  11. Python求水仙花数
  12. 基于自动编码器特征抽取的分类实战
  13. 基于STM32的STM8脱机编程器源码分享
  14. 电商营销方式抢购,秒杀Redis原子减decr方法作为剩余库存判断条件的实现方式(1)
  15. Python:实现矩阵的Schur complement舒尔补算法(附完整源码)
  16. 推荐几个好用的临时邮箱生成工具网站
  17. CC1310开发笔记
  18. 模拟集成电路设计与分析——全差分放大器
  19. 上海都有哪些牛逼的互联网公司?
  20. 论文阅读《Direct Sparse Odometry》2

热门文章

  1. 全志A31编译环境搭建
  2. 全世界最像人的「机器人」,本身就是人
  3. 【论文】Poly-yolo: 改进anchor分配问题
  4. Java实现颜色渐变效果
  5. newifi安装php,新路由(newifi)登录地址安装设置步骤
  6. java计算机毕业设计大学生学籍管理系统源码+数据库+系统+lw文档+部署
  7. laydate动态设定时间范围
  8. 变形金刚ol服务器维护,变形金刚OL5月27日停机更新延迟开服公告
  9. 黄金斗士原生android,联想黄金斗士S8手机怎么样 黄金斗士S8真机评测详细图解
  10. STM32H7xx 串口DMA发送接收(LL库)