很多人问过我一个问题搞信息安全为什么还要沉下心去学JavaEE开发我的回答通常是——你不懂业务代码是怎么写出来的就不知道漏洞到底是从哪个环节混进去的。小迪安全的day32~40这8天课程正好把JavaEE开发这条线串起来了从Servlet基础到三层架构再到Web应用安全编码内容密度相当大。这篇文章我结合自己的学习和实操经验把8天课程的精华、VSCode配置JavaEE开发环境的具体步骤、以及我踩过的坑一并整理出来给正在学JavaEE开发或者需要从安全视角看懂Java Web应用的读者做个参考。先说清楚这套内容适合谁刚接触JavaWeb开发、知道Servlet和JSP但没系统写过三层架构的学过一点Java的朋友以及做安全测试但看不懂Java项目代码的同行。无论你属于哪一类看完这篇都能少走很多弯路。而且我会把VSCode配置JavaEE语言环境的步骤尽量写得可以直接照着抄毕竟这也是很多人刚上手时最卡壳的一步。1. 拆解day32~40JavaEE开发到底在讲什么1.1 为什么一门安全课要花8天讲JavaEE开发很多人觉得安全课就应该天天讲漏洞、打靶场、分析攻击流量为什么要花8天讲开发其实道理很简单你不懂“正常”是什么样子就识别不了“异常”。JavaEE是过去十几年企业级Web应用最主流的的技术栈银行、电商、OA系统有大量后端服务是用Java写的。安全测试里最常碰到的SQL注入、XSS、越权、文件上传漏洞几乎都发生在JavaWeb应用的特定代码位置上。只有理解了Servlet的生命周期、过滤器的执行顺序、Session的存储机制你才能准确推断一个漏洞到底在哪个环节触发、影响范围有多大、能不能被利用。这8天课程的安排很聪明。它不是把JavaEE开发的所有细节都塞给你而是挑出安全人员最需要理解的那条主线Web应用是怎么从请求到响应的、数据是怎么流转的、认证和授权是建立在什么机制上的。跟着这条线走下来再回头去看漏洞报告里那些“代码审计发现”的结论你才能真正看懂它在说什么。1.2 八天课程的知识脉络我回忆了一下day32到day40讲的主要内容大致分为四个阶段第一阶段JavaEE基础储备。包括JDK环境、IDE选择、Maven工程结构、Servlet和JSP的基础写法。这个阶段主要解决“能不能把项目跑起来”的问题。第二阶段Web组件核心机制。重点讲Servlet生命周期、请求转发与重定向、Session与Cookie的区别、Filter过滤器、Listener监听器。这些都是JavaWeb应用的骨架。第三阶段经典三层架构与业务开发。引入Service层、DAO层、Controller层的分层方式手写一个从页面到数据库的完整业务流程包括登录认证、列表展示、增删改查。第四阶段安全编码意识与漏洞消除。针对前面写的业务代码做安全加固讲解SQL注入、XSS、CSRF、越权问题的成因和编码层防御方法。这个顺序特别像一个人从零搭一个真实项目的流程。许多从框架入手的开发者其实不懂底层Servlet做了什么8天课补的正是这块空白。比如Spring MVC的本质就是在前端控制器DispatcherServlet基础上封装出来的你理解Servlet之后再看框架源码就不会觉得它是黑盒。2. VSCode配置JavaEE开发环境实录2.1 基础环境三板斧JDK、Maven、Tomcat在配置VSCode之前要先装好JavaEE开发跑起来需要的底层环境。我建议按这个顺序装避免后面不断折腾。第一是JDK。不要装最新版尽量选Java 8或者Java 11这两个版本在企业项目和大多数教程里兼容性最好。我用的OpenJDK 11。装完在命令行执行java -version能正常输出版本信息就行。注意一定要配好JAVA_HOME环境变量很多工具依赖它找JDK路径。Windows下在系统变量里新建JAVA_HOME指向JDK安装目录再在Path里加上%JAVA_HOME%\bin。第二是Maven。JavaEE项目里依赖管理基本都靠它。去Apache官网下载二进制压缩包解压到一个纯英文路径下然后配置MAVEN_HOME和Path。重点要改的是Maven的配置文件settings.xml里面要设置本地仓库路径和阿里云镜像不然后面拉依赖会慢到怀疑人生。镜像配置写在mirrors标签里用阿里云的central镜像我后面会放代码。第三是Tomcat。选Tomcat 9或者Tomcat 8.5都支持Servlet 4.0和JSP 2.3足够用了。下载解压后不要直接双击启动先在命令行到Tomcat的bin目录下执行startup.batWindows或者startup.shLinux/mac确认8080端口能访问到默认首页。之后再关联到VSCode里。这三种组件装完基础环境就立住了。有一点想提醒所有路径尽量别带空格和中文否则后面VSCode调试时会出现各种奇怪的“找不到类”或“无法加载资源”问题。2.2 VSCode插件与配置步骤VSCode本身只是一个编辑器要把它变成JavaEE开发环境需要装一组扩展。核心是这四个Extension Pack for Java微软官方的Java扩展包自动包含语言服务、调试器、Maven支持、测试支持。Tomcat for Java让VSCode直接识别Tomcat服务器一键启动、停止、部署项目。Spring Boot Extension Pack如果后面要写Spring Boot项目可以装。纯Servlet阶段的可以暂时不装。Maven for Java通常Extension Pack for Java里已经带了不需要单独装。装完插件后按CtrlShiftP打开命令面板搜索“Java: Configure Classpath”或者直接新建Java文件VSCode会提示你选择JDK。首次使用可能需要几分钟让语言服务初始化。我重点说一下Tomcat插件的配置。安装Tomcat for Java后在VSCode左侧会出现一个“Tomcat Servers”面板。点加号选择Tomcat安装目录它就会自动识别。然后右键Tomcat服务选择“Open Debug Configuration”确认调试端口和启动命令没问题。这样后续就能在VSCode里直接启动Tomcat并断点调试。还有一个很关键的配置文件settings.json。建议在工作区.vscode文件夹下加这些内容能明显减少中文乱码和编译问题{ java.configuration.runtimes: [ { name: JavaSE-11, path: C:\\Program Files\\Java\\jdk-11.0.18, default: true } ], java.compile.nullAnalysis.mode: automatic, files.encoding: utf8, maven.executable.path: D:\\apache-maven-3.8.8\\bin\\mvn.cmd, terminal.integrated.defaultProfile.windows: Command Prompt }这里面的JDK路径、Maven路径都要按你机器实际位置改。files.encoding设为utf8后配合POM里设置的project.build.sourceEncoding乱码问题基本能根治。2.3 用Maven骨架创建JavaWeb项目VSCode里创建一个JavaWeb项目我推荐直接用Maven的maven-archetype-webapp骨架比手动建目录规范得多。在VSCode命令面板执行“Maven: Create Maven Project”然后选maven-archetype-webapp填写groupId、artifactId和包名。创建完成后项目结构是这样的src/main/java src/main/resources src/main/webapp src/main/webapp/WEB-INF/web.xml pom.xml创建完成第一件事检查pom.xml。maven-archetype-webapp骨架默认只带JUnit依赖没有Servlet依赖。需要在dependencies里手动加入Servlet API和JSP API。要注意这两个依赖的scope必须设为provided因为Tomcat容器自带了这些类如果打成war包又把它们带进去运行时会产生类冲突。dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency然后还要在pom.xml里配置编译插件和打包插件比如maven-compiler-plugin指定Java版本maven-war-plugin生成war包。配置好后右键项目根目录选“Run on Tomcat”或通过Tomcat Servers面板把项目添加到服务器浏览器访问http://localhost:8080/项目名/看到默认的index.jsp页面就算环境通了。3. 核心开发实操解析3.1 三层架构与MVC拆分day32~40课程里很强调“代码分层”因为我见过的很多新手把数据库查询、业务判断、页面跳转全写在一个Servlet里几百行代码混成一团。这种写法不仅后期没法维护而且在安全审计时几乎分不清哪里是输入、哪里是逻辑、哪里是输出漏洞定位极其痛苦。经典三层架构就是Controller层也叫表现层、Service层、DAO层。Controller层只负责接收请求参数、调用Service、返回页面或JSONService层处理业务逻辑比如校验用户名密码、判断权限DAO层专门跟数据库打交道执行SQL并返回结果。每层的职责明确之后你一眼就能看出“用户输入是从Controller进DAO拼接进SQL”那么SQL注入点就清楚了修复方案也很明确——在DAO层改预编译。MVC和三层架构并不冲突。MVC强调的是模型、视图、控制器三个角色的划分而三层架构强调的是职责分层。实践中往往是MVC中的Controller对应Controller层Model对应Service层加DAO层View对应JSP页面。理解这个层次关系后后面学习Spring MVC、MyBatis就非常顺畅。3.2 登录模块代码实战我选一个登录功能作为完整案例因为登录涉及输入校验、数据库查询、Session管理这个流程几乎覆盖了JavaEE开发的大部分核心知识点。先写一个实体类User包含id、username、password字段。这里不推荐手动写一堆getter/setter但教学阶段建议手写一遍能加深理解。DAO层负责查询用户。重点看这里使用了PreparedStatement预编译而不是拼接字符串SQL。千万记住开发阶段就养成的习惯任何SQL都不要直接拼接用户输入。拿字符串拼接写出来的代码哪怕功能正常在安全视角看也是一个必现的SQL注入漏洞。public class UserDao { public User findByUsernameAndPassword(String username, String password) { String sql SELECT * FROM user WHERE username ? AND password ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { User user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); return user; } } } catch (SQLException e) { e.printStackTrace(); } return null; } }这里DBUtil是封装了数据库连接的工具类内部读取配置、创建DataSource。实际项目里不要用DriverManager.getConnection()每次创建连接而是用连接池技术。后面我把详细配置列出来。Service层调用DAO层同时可以叠加额外逻辑比如指定时间窗口内登录失败次数限制。一个简单的做法是引入LoginAttemptService把用户名作为key存到ConcurrentHashMap里记录失败次数超过5次就锁定一段时间。这个代码虽然简单但能有效防止暴力破解。Controller层接收前端传来的参数调用Service根据结果决定转发还是重定向。WebServlet(/login) public class LoginServlet extends HttpServlet { private UserService userService new UserService(); protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); User user userService.login(username, password); if (user ! null) { req.getSession().setAttribute(currentUser, user); resp.sendRedirect(req.getContextPath() /index.jsp); } else { req.setAttribute(errorMsg, 用户名或密码错误); req.getRequestDispatcher(/login.jsp).forward(req, resp); } } }注意到密码校验我直接传了明文password真实项目里密码不能明文存至少要用BCrypt哈希。在小迪安全课程里也提到这一点。所以我在Service层里加了一个PasswordUtil.matches(rawPassword, encodedPassword)方法用BCrypt验证。这个细节很容易被初学者忽略但它直接关系到数据库泄露后密码的安全性。3.3 过滤器和安全编码细节登录功能做完后还有个关键点如何保护其他页面不被未登录用户访问。总不能每个Servlet都写一遍Session判断。这时过滤器Filter就派上用场了。以WebFilter(/*)定义一个全局过滤器在doFilter方法里判断当前会话是否包含登录用户。如果是登录请求或静态资源则直接放行否则重定向到登录页。WebFilter(/*) public class AuthFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; HttpSession session request.getSession(false); String path request.getRequestURI(); if (path.endsWith(/login.jsp) || path.contains(/login) || path.endsWith(.css) || path.endsWith(.js)) { chain.doFilter(req, resp); return; } if (session null || session.getAttribute(currentUser) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }这个过滤器就是Spring Security拦截链路的前身。理解它的执行顺序对安全分析很重要过滤器链在Servlet执行之前执行所以越权、未认证这类漏洞要么是过滤器没配置好、要么是过滤器放行了不该放行的路径。比如用path.contains(/login)去匹配攻击者访问/loginAdmin也可能被放行这就是典型的路由匹配绕过。除了认证授权XSS的防御也要写在编码习惯里。在JSP页面输出动态内容时必须对用户输入做HTML转义。JSP标准里可以直接用${fn:escapeXml(param)}或者引入JSTL的c:out value${content}/。我在代码里手动写了一个HtmlUtil.escape()方法把所有 转成实体字符。做安全编码不是为了应付检查而是这些写法能在源头上把漏洞概率降下来。另外数据库连接的部分我实际使用的是HikariCP连接池因为在JavaEE开发里连接池是必需品。配置如下dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId version4.0.3/version /dependencyjdbcUrljdbc:mysql://localhost:3306/security_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai usernameroot passwordyourpassword maximumPoolSize10连接池的好处是复用连接、提高响应速度同时还能通过检测空闲连接来避免超时断开。开发时使用连接池还有一个好处配合事务管理更容易。比如转账、下单这种需要多步写操作的业务只有拿到同一个连接才能保证原子性。新手最容易犯的错是DAO层每次自己获取连接导致多个DAO操作不在同一事务里。正确做法是在Service层管理事务把一个连接传入DAO层。4. 常见问题与排查技巧实录4.1 环境问题速查表我在重新搭VSCode JavaEE环境以及跑课程示例项目的时候遇到过不少问题。整理成表格方便你直接对照排查。症状可能原因解决方法Tomcat启动后页面404war包未部署成功或访问路径不对确认项目名和URL路径检查Tomcat面板中部署状态观察Console日志端口被占用之前有Tomcat或其他进程占用了8080命令行执行netstat -anoJava项目运行提示“无法解析 javax.servlet.*”pom缺少Servlet依赖或scope错误添加javax.servlet-api依赖scope设为provided中文乱码页面编码、Java文件编码、请求编码不一致统一使用UTF-8在web.xml配置CharacterEncodingFilter代码中req.setCharacterEncodingMaven下载依赖慢使用的是中央仓库默认地址修改settings.xml配置阿里云镜像VSCode能看到断点但不命中Tomcat是以外部进程启动未开启调试使用Tomcat for Java的Debug模式启动服务器确保调试端口正确修改java代码后不生效Tomcat未热部署右键项目选择Redeploy或调试时保存自动编译Session一会儿就失效web.xml或Tomcat默认超时太短在web.xml设置session-config的timeout为30分钟这个表格里的每个问题我都实际遇到过特别是中文乱码几乎贯穿了第一个JavaWeb项目的整个生命周期。我后来总结出一个固定套路所有Java文件保持UTF-8、JSP页面设置pageEncodingUTF-8、web.xml里加一个编码过滤器强制所有请求和响应使用UTF-8基本能解决95%的乱码问题。4.2 我在配置VSCode时踩过的三个坑第一个坑是JDK和Maven版本不匹配。我一开始装了JDK 17又用了老版本的Maven 3.6结果创建Maven项目时一直报错提示”不受支持的类文件主要版本“。后来把Maven升到3.8.8同时把JDK降到11问题立刻消失。建议后续版本选择上不要追新JDK 11Maven 3.8系列是最稳定的组合。第二个坑是Tomcat插件的调试端口。Tomcat for Java插件默认会用JDPA调试端口但如果电脑上同时运行了多个Tomcat实例端口会冲突导致启动报“Address already in use”。解决方法是打开Tomcat的catalina.bat或者插件的配置把-agentlib:jdwptransportdt_socket,servery,suspendn,address*:8000里的8000改成其他端口。改成9000之后就没再冲突过。第三个坑是Maven镜像配置。不配置阿里云镜像时下载一个Spring依赖可能要十几分钟甚至直接超时。配置方法是在settings.xml的mirrors节点里加这段mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror配置完记得重启VSCode或让Maven重新加载项目。这个方法立竿见影依赖秒下。4.3 从安全视角复盘这段开发学习学完day32~40之后我重新去看之前收集过的Java漏洞案例思路完全不一样了。以前我看到一个SQL注入漏洞报告只知道攻击者在参数里拼了 or 11--现在我会习惯性打开源码去找DAO层的SQL语句看是不是用了PreparedStatement看到越权漏洞报告我会去看Controller层的接口有没有做当前用户归属校验看到XSS漏洞我在前端输出的地方找escape逻辑。这就是我做JavaEE开发学习的最大收获不再把安全问题看成某个孤立漏洞而是看成一个编码习惯问题。很多漏洞其实不是安全工程师补救出来的而是开发人员在一开始就埋下的。如果我们在写代码时能提前想到“这段SQL不能拼接”“这个页面输出需要转义”“这个接口必须校验身份”应用的安全性会上一个台阶。所以我也建议纯开发方向的同学不要排斥安全编码的内容它不算额外负担只是把“正常代码”的标准提高了一点。纯安全方向的同学也要硬着头皮把Servlet、Filter、Session、Maven这套基本功啃下来哪怕不写完整项目至少要会看代码、会跑环境、会定位漏洞所在的代码位置。这8天课程里还有一个让我印象很深的思想开发环境和漏洞验证环境是通用的。你搭JavaEE环境时用的是Tomcat、MySQL、Maven做渗透测试时照样要用这些工具来起一个本地靶场。与其到用的时候再慌不如趁学习阶段把环境、代码、调试流程全部走一遍。我这次整理VSCode配置JavaEE的完整过程也算是对自己折腾半天的一个复盘。如果你也卡在环境上直接照着我前面的步骤来基本上20分钟内就能看见自己的第一个JavaWeb应用在浏览器里跑起来。跑通之后记得自己动手改一改代码把登录失败次数限制加上、把某个输出加个转义、试试用过滤器拦一个未授权路径。这些动手改代码的过程比单纯看完课程更重要。等你练到能随手画出Servlet请求流程图、能很快定位DAO层SQL拼接问题时JavaEE开发这条线才算真正吃透了。
阅读完成 · 觉得有帮助?