热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Shiro权限绕过漏洞分析

 前言前段时间遇到通过分号绕过nginx层屏蔽并顺利访问到Springboot项目actuator端点的问题,修复过程中偶然发现当项目使用shiro组件时,若将shiro升级到1.6.0可间接修复分号

 

前言

前段时间遇到通过分号绕过nginx层屏蔽并顺利访问到Springboot项目actuator端点的问题,修复过程中偶然发现当项目使用shiro组件时,若将shiro升级到1.6.0可间接修复分号绕过的问题,当请求url中包含分号时响应状态码为400;

考虑到shiro主要用来执行身份验证授权等,理论上不适合直接阻断存在分号的请求;

为搞明白此问题,决定对shiro的权限校验问题进行整理学习,下面为常见的shiro权限绕过漏洞分析修复过程。

 

Shiro Filter

学习shiro权限绕过漏洞之前,有必要了解下shiro filter的过滤过程;

一个http请求过来,首先经过web容器的处理(这里默认为tomcat)被投放到相应的web应用,web应用会通过过滤器Filter链式的对http请求进行预处理,这里将会经过shiro的Filter(SpringShiroFilter)处理:

org.apache.catalina.core.ApplicationFilterChain#internalDoFilter --> org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter -->
org.apache.shiro.web.servlet.AbstractShiroFilter#doFilterInternal -->
org.apache.shiro.web.servlet.AbstractShiroFilter#executeChain

shiro的Filter执行过会通过getExecutionChain()获取执行链并执行对应的doFilter函数:

重点在获取chain的org.apache.shiro.web.servlet.AbstractShiroFilter#getExecutionChain中;

首先会尝试获取到在springboot启动时加载的shiro配置文件中配置的Shiro filterChains(resolver)并判断是否为null,当为null则返回原始过滤器链origChain,当不为空时则尝试通过org.apache.shiro.web.filter.mgt.FilterChainResolver#getChain方法根据当前请求的url使用Ant模式获取相应的拦截器链 FilterChain代理(resolved),否则返回原始过滤器链origChain:

protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
FilterChain chain = origChain;
FilterChainResolver resolver = getFilterChainResolver();
if (resolver == null) {
log.debug("No FilterChainResolver configured. Returning original FilterChain.");
return origChain;
}
FilterChain resolved = resolver.getChain(request, response, origChain);
if (resolved != null) {
log.trace("Resolved a configured FilterChain for the current request.");
chain = resolved;
} else {
log.trace("No FilterChain configured for the current request. Using the default.");
}
return chain;
}

其中获取shiro对应的FilterChain代理是在org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain中完成,主要通过获取所有的filter链(filterChainManager)及requestURI,并循环遍历filterChainManager进行匹配,当匹配时则直接返回相对应的FilterChain代理,否则返回null:

附上filterChainManager接口说明:

public interface FilterChainManager {
// 得到注册的拦截器
Map getFilters();
// 获取拦截器链
NamedFilterList getChain(String chainName);
// 是否有拦截器链
boolean hasChains();
// 得到所有拦截器链的名字
Set getChainNames();
// 使用指定的拦截器链代理原始拦截器链
FilterChain proxy(FilterChain original, String chainName);
// 注册拦截器
void addFilter(String name, Filter filter);
// 注册拦截器
void addFilter(String name, Filter filter, boolean init);
// 根据拦截器链定义创建拦截器链
void createChain(String chainName, String chainDefinition);
// 添加拦截器到指定的拦截器链
void addToChain(String chainName, String filterName);
// 添加拦截器(带有配置的)到指定的拦截器链
void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) throws ConfigurationException;
}

最终链式执行过滤器:

org.apache.catalina.core.ApplicationFilterChain#doFilter --> org.apache.catalina.core.ApplicationFilterChain#internalDoFilter

执行完过滤器后将调用servlet.service,进而执行controller解析及service等:

javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse):

接下来的SpringMVC controller解析部分详情可参见下面CVE-2020-1957漏洞分析部分。

 

漏洞环境

可参考:

https://github.com/apache/shiro/releases

https://github.com/ttestoo/java-sec-study/tree/main/sec-shiro/java-shiro-bypass

 

shiro权限绕过 CVE-2020-1957



利用条件

Apache Shiro <1.5.2


利用过程

1、正常情况下访问/hello/a会进行跳转:http://127.0.0.1:9091/hello/a

2、可通过分号进行绕过:

http://127.0.0.1:9091/;/hello/a

http://127.0.0.1:9091/aa/..;test=123/admin/index


漏洞分析

shiro filter主要过程上述部分已简单介绍,其中根据分号绕过可初步判断问题可能出现在获取requestURI处,毕竟是拿requestURI和shiro配置的FilterChain进行匹配的,也就是说通过分号使得shiro filter过程的requestURI能绕过shiro的Ant格式的规则匹配;

可以直接在org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain中的String requestURI = getPathWithinApplication(request); 处下断点进行调试:

注意这里测试过程中URL为:http://127.0.0.1:9091/aa/..;test=123/admin/index

跟进getPathWithinApplication函数,将通过WebUtils.getPathWithinApplication —> WebUtils.getRequestUri 获取requestURI:

最终还是通过request.getRequestURI获取请求中的URI,即:/aa/..;test=123/admin/index

获取到请求中的URI后,将通过org.apache.shiro.web.util.WebUtils#normalize进行标准化处理,其中参数调用了decodeAndCleanUriString函数处理,在decodeAndCleanUriString中可以清晰的看到根据 ; 对uri进行了分割,并获取到 ; 之前的部分,即/aa/..

且在normalize函数中,主要标准化处理内容如下:


  • \ —> /

  • // —> /

  • /./ —> /

  • /../ —> /

private static String normalize(String path, boolean replaceBackSlash) {
if (path == null)
return null;
// Create a place for the normalized path
String normalized = path;
if (replaceBackSlash && normalized.indexOf('\\') >= 0)
normalized = normalized.replace('\\', '/');
if (normalized.equals("/."))
return "/";
// Add a leading "/" if necessary
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index <0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index <0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index <0)
break;
if (index == 0)
return (null); // Trying to go outside our context
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Return the normalized path that we have completed
return (normalized);
}

由于此时传入的为经过decodeAndCleanUriString处理后的值(/aa/..),所以这里经过normalize处理后结果不变:

也就是说此时通过WebUtils.getRequestUri获取到的requestUri的值为/aa/..

且getPathWithinApplication后的值也为/aa/..

接下来将对requestURI和在shiro配置文件中配置的过滤规则filterChains进行匹配,则/aa/..不会和任何规则匹配成功,返回null:

至此,我们通过在请求url中添加 ; 成功绕过了shiro的filter过滤匹配,并成功进入SpringMVC controller解析过程,其中入口为SpringMVC的DispatcherServlet.doService():

org.apache.catalina.core.ApplicationFilterChain#internalDoFilter --> javax.servlet.Servlet#service --> javax.servlet.http.HttpServlet#service --> javax.servlet.http.HttpServlet#doGet --> org.springframework.web.servlet.FrameworkServlet#processRequest -->
org.springframework.web.servlet.DispatcherServlet#doService -->

在DispatcherServlet.doService中将调用核心的doDispatch方法进行下一步处理:

其中doDispatch主要处理逻辑如下:


  1. checkMultipart 检查是不是文件上传请求,如果是,则对当前 request 重新进行包装,如果不是,则直接将参数返回;

  2. 根据当前请求,调用 getHandler 方法获取请求处理器,如果没找到对应的请求处理器,则调用 noHandlerFound 方法抛出异常或者给出 404;

  3. getHandlerAdapter 方法,根据当前的处理器找到处理器适配器;

  4. 然后处理 GET 和 HEAD 请求头的 Last_Modified 字段。当浏览器第一次发起 GET 或者 HEAD 请求时,请求的响应头中包含一个 Last-Modified 字段,这个字段表示该资源最后一次修改时间,以后浏览器再次发送 GET、HEAD 请求时,都会携带上该字段,服务端收到该字段之后,和资源的最后一次修改时间进行对比,如果资源还没有过期,则直接返回 304 告诉浏览器之前的资源还是可以继续用的,如果资源已经过期,则服务端会返回新的资源以及新的 Last-Modified;

  5. 接下来调用拦截器的 preHandle 方法,如果该方法返回 false,则直接 return 掉当前请求;

  6. 接下来执行 ha.handle 去调用真正的请求,获取到返回结果 mv;

  7. 接下来判断当前请求是否需要异步处理,如果需要,则直接 return 掉;如果不需要异步处理,则执行 applyDefaultViewName 方法,检查当前 mv 是否没有视图,如果没有(例如方法返回值为 void),则给一个默认的视图名;

  8. processDispatchResult 方法对执行结果进行处理,包括异常处理、渲染页面以及执行拦截器的 afterCompletion 方法都在这里完成;

  9. 最后在 finally 代码块中判断是否开启了异步处理,如果开启了,则调用相应的拦截器;如果请求是文件上传请求,则再调用 cleanupMultipart 方法清除文件上传过程产生的一些临时文件。

其中我们关心的是获取请求处理器的过程,即getHandler方法实现细节:

首先Spring会循环所有注册的HandlerMapping并返回第一个匹配的HandlerExecutionChain:

对于mapping为RequestMappingHandlerMapping时,则会调用org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler进行获取对应的handler,

在getHandler中调用getHandlerInternal方法,并在其中进行调用getLookupPathForRequest—>getPathWithinServletMapping解析请求路径lookupPath:

对于getPathWithinServletMapping中首先通过getPathWithinApplication获取请求URI在web应用中的路径,其中经过如下调用链:

最终在org.springframework.web.util.UrlPathHelper#getRequestUri中通过request.getRequestURI()获取请求的uri,即/aa/..;test=123/admin/index,并通过decodeAndCleanUriString方法对uri进行处理:

decodeAndCleanUriString方法中主要做了三件事:

1、调用removeSemicolonContent方法对uri进行处理,其中将分号及后面的key-value进行了去除得到新的requestUri为/aa/../admin/index:

2、通过调用decodeRequestString进行URL解码:

3、通过调用getSanitizedPath将//替换为/:

至此经过decodeAndCleanUriString方法处理后最终获取到的uri为/aa/../admin/index,即getPathWithinApplication返回的结果pathWithinApp的值也为/aa/../admin/index:

接下来回到getPathWithinServletMapping中,此时pathWithinApp值为/aa/../admin/index,servletPath为/admin/index,正常情况下将通过getRemainingPath方法将pathWithinApp中servletPath给截取掉,但此时由于两者值无法截取成功返回为null:

由于path为null,则进入else这种特殊情况,最终返回servletPath,即/admin/index:

即最终获取到的lookupPath值为/admin/index,并根据lookupPath的值寻找相对应的handlerMethod为com.ttestoo.bypass.controller.LoginController#admin_index():

至此,SpringMVC中获取handler的过程已结束,成功获取到/admin/index相对应的handler方法,并将继续获取HandlerAdapter,并执行HandlerAdapter的handle方法利用反射机制执行/admin/index相对应的controller方法com.ttestoo.bypass.controller.LoginController#admin_index():

总结:

当我们发起请求http://127.0.0.1:9091/aa/..;test=123/admin/index时,经过shiro filter进行权限校验,此时shiro解析到的路径为/aa/..不会和任何规则匹配成功,从而通过了shiro的权限校验;

接下来会由springmvc进行controller解析,此时springmvc解析到的路径为/admin/index,并获取到/admin/index对应的handler方法admin_index,从而正常的执行service并得到最终的响应。

漏洞本质:

当路径中包含特殊字符时,shiro解析得到的路径和SpringMVC解析得到的路径不一致,导致可正常通过shiro的权限校验并正常的完成service的执行获取执行结果。


利用场景

在实际场景中每个API会通过网关层统一校验或@RequiresPermissions注解等方式校验所需访问权限,此漏洞仅能绕过shiro全局的Filter校验,无法绕过API配置的访问权限;

个人理解此问题在实战中利用场景相对有限。


修复方式

根据官方commit记录,可知在1.5.2开始,在org.apache.shiro.web.util.WebUtils#getRequestUri中获取uri的方式从request.getRequestURI()换成了request.getContextPath()+request.getServletPath()+request.getPathInfo()组合的方式:

此时请求http://127.0.0.1:9091/aa/..;test=123/admin/index获取到的url为/admin/index,无法绕过shiro的权限校验:

 

shiro权限绕过 CVE-2020-11989



利用条件

主要是针对CVE-2020-1957修复后的绕过探索,主要两种方式:


  • URL双编码:Apache Shiro = 1.5.2 & controller需为类似”/hello/{page}”的方式

  • 分号绕过:Apache Shiro <1.5.3 & server.servlet.context-path不为根/



利用过程

URL双编码

shiro版本需为1.5.2,访问http://127.0.0.1:9091/hello/test,被shiro权限校验拦截:

访问http://127.0.0.1:9091/hello/te%25%32%66st可直接绕过权限校验:

分号绕过

需要配置server.servlet.context-path:

server.servlet.context-path=/test

http://127.0.0.1:9091/test/hello/test

http://127.0.0.1:9091/a/..;a=1/test/hello/test


漏洞分析

URL双编码分析

首先发起http请求时,若url中存在URL编码字符,则会被容器进行一次URL解码,此时/hello/te%25%32%66st —> /hello/te%2fst,接下来则同CVE-2020-1957过程一样,在shiro处理过程中会在org.apache.shiro.web.util.WebUtils#getPathWithinApplication中通过getRequestUri函数获取uri:

在org.apache.shiro.web.util.WebUtils#getRequestUri中首先通过request.getContextPath()+request.getServletPath()+request.getPathInfo()组合的方式获取uri为://hello/te%2fst

接着在进入normalize函数进行格式化处理时,传入的参数经过了decodeAndCleanUriString方法的处理,其中通过调用org.apache.shiro.web.util.WebUtils#decodeRequestString方法,利用URLDecoder.decode进行了URL解码为://hello/te/st

继续进入normalize函数,将//替换为/,最终获取到的uri为:/hello/te/st

接下来就同上面shiro过程一致了,/hello/te/st不会和任何的规则匹配,成功解析controller并执行相对应的service获取响应结果:

补充,在1.5.1及之前版本中,获取uri采用request.getRequestURI方式,获取到的为URL双编码的值,shiro进行一次解码并格式化处理后为/hello/te%2fst,则会和/hello/*进行匹配:

分号绕过分析

当请求为http://127.0.0.1:9091/a/..;a=1/test/hello/test时,

同URL双编码主要区别在经过request.getContextPath()+request.getServletPath()+request.getPathInfo()组合获取到的uri为:/a/..;a=1/test//hello/test

request.getContextPath() --> /a/..;a=1/test
request.getServletPath() --> /hello/test
request.getPathInfo() --> null

接着经过org.apache.shiro.web.util.WebUtils#decodeAndCleanUriString处理后,会根据 ; 进行分割,最终uri结果为:/a/..

从而绕过shiro的权限校验,而接下来则和cve-2020-1957流程一致,springmvc会将 ; 进行剔除,最终根据/a/../test/hello/test,即/test/hello/test成功解析controller并执行service获取响应结果:


修复方式

在1.5.3中,获取uri方式改成了getServletPath(request) + getPathInfo(request)组合的方式,且去除了解码过程:

此时,同样的请求http://127.0.0.1:9091/a/..;a=1/test/hello/test,获取到的requestURI为:/hello/test

请求http://127.0.0.1:9091/hello/te%25%32%66st获取到的requestURI为:/hello/te%27st

 

shiro权限绕过 CVE-2020-13933



利用条件

Apache shiro<=1.5.3 即 Apache Shiro <1.6.0

controller需为类似”/hello/{page}”的方式利用过程


利用过程

http://127.0.0.1:9091/hello/test

http://127.0.0.1:9091/hello/%3btest


漏洞分析

当发起请求http://127.0.0.1:9091/hello/%3btest时,

首先容器会进行URL解码,/hello/%3btest —> /hello/;test

进入shiro处理,org.apache.shiro.web.util.WebUtils#getPathWithinApplication中最终结果即requestURI为/hello/:

getServletPath(request) --> /hello/;test
getPathInfo(request) --> ""
removeSemicolon中根据;进行分割

而/hello/不会和/hello/*匹配,顺利进入controller解析并执行service获取响应结果:


修复方式

在1.6.0中,执行shiro过滤器时增加了preHandle方法进行判断是否继续执行:

判断内容主要为:若请求URI中包含分号、反斜杠、非ASCII字符(均可配置),则直接响应400

核心逻辑均在新增的类org.apache.shiro.web.filter.InvalidRequestFilter中:https://shiro.apache.org/static/1.6.0/apidocs/org/apache/shiro/web/filter/InvalidRequestFilter.html

 

shiro权限绕过 CVE-2020-17523



利用条件

Apache Shiro <1.7.1

controller需为类似”/hello/{page}”的方式


利用过程

空格绕过

1、http://127.0.0.1:9091/hello/test

2、http://127.0.0.1:9091/hello/%20

西式句号 全路径绕过

需配置开启全路径匹配:

1、http://127.0.0.1:9091/hello/.


漏洞分析

空格绕过

当发起http://127.0.0.1:9091/hello/%20请求时,

首先经过容器URL解码,/hello/%20 —> /hello/空格

发现在shiro进行匹配过程中,/hello/* 和 /hello/空格 不匹配:

在org.apache.shiro.util.AntPathMatcher#doMatch函数中,/hello/* 和 /hello/空格 经过tokenizeToStringArray函数处理后的结果中/hello空格仅剩/hello:

跟进tokenizeToStringArray方法可知,调用过程中,trimTokens参数值为true:

而当trimTokens为true时,则会调用trim(),此时/hello/后面的空格将会被丢弃:

在接下来的判断过程中,匹配结果为false,即/hello/* 和 /hello/空格 不匹配从而导致shiro的权限绕过:

西式句号 全路径绕过

当请求http://127.0.0.1:9091/hello/.时,首先经过org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getPathWithinApplication处理时,会被normalize函数将/hello/.最后面的 . 删除掉,最终requestURI为/hello/:

在org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain处理过程中,由于此时requestURI以/结尾,则将会把最后一个/删除,变成/hello:

而/hello和/hello/*不匹配导致shiro权限绕过:

但是,此时SpringMVC进行controller解析时,请求路径为/hello/%2e,spring中.和/默认是作为路径分割符的,不会参与到路径匹配,此时将解析controller失败,返回404:

即,虽然绕过了shiro的权限校验,但默认无法解析到controller,也就无法执行想要的service;

特殊情况:

当手工配置开启springboot的全路径匹配时,可成功执行:

//开启全路径匹配
@ServletComponentScan
@SpringBootApplication
public class Application extends SpringBootServletInitializer implements BeanPostProcessor {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping) bean).setAlwaysUseFullPath(true);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}


修复方式

1、将tokenizeToStringArray函数的trimTokens参数设置为false,防止空格被抛弃:

2、将剔除结尾/的过程移到匹配的下方:

 

总结

开头所说的利用分号绕过了nginx的403屏蔽,请求到springboot项目后携带分号解析成功,而当使用了shiro 1.6.0后,url中携带分号则直接报错400,原因就很清晰了,因为在1.6.0中增加了org.apache.shiro.web.filter.InvalidRequestFilter类,其中会判断请求中包含分号时响应400状态码;

shiro的权限绕过,本质还是shiro对uri的解析规则和后端开发框架的解析规则不一样所导致。

 

巨人的肩膀

https://github.com/apache/shiro/commit/3708d7907016bf2fa12691dff6ff0def1249b8ce

https://shiro.apache.org/static/1.6.0/apidocs/org/apache/shiro/web/filter/InvalidRequestFilter.html

https://github.com/apache/shiro/commit/0842c27fa72d0da5de0c5723a66d402fe20903df

https://shiro.apache.org/security-reports.html

https://xlab.tencent.com/cn/2020/06/30/xlab-20-002/

https://mp.weixin.qq.com/s/yb6Tb7zSTKKmBlcNVz0MBA

https://github.com/jweny/shiro-cve-2020-17523

https://segmentfault.com/a/1190000039703198

……


推荐阅读
  • 本文详细解析了如何使用 jQuery 实现一个在浏览器地址栏运行的射击游戏。通过源代码分析,展示了关键的 JavaScript 技术和实现方法,并提供了在线演示链接供读者参考。此外,还介绍了如何在 Visual Studio Code 中进行开发和调试,为开发者提供了实用的技巧和建议。 ... [详细]
  • 如何撰写PHP电商项目的实战经验? ... [详细]
  • Java Web开发中的JSP:三大指令、九大隐式对象与动作标签详解
    在Java Web开发中,JSP(Java Server Pages)是一种重要的技术,用于构建动态网页。本文详细介绍了JSP的三大指令、九大隐式对象以及动作标签。三大指令包括页面指令、包含指令和标签库指令,它们分别用于设置页面属性、引入其他文件和定义自定义标签。九大隐式对象则涵盖了请求、响应、会话、应用上下文等关键组件,为开发者提供了便捷的操作接口。动作标签则通过预定义的动作来简化页面逻辑,提高开发效率。这些内容对于理解和掌握JSP技术具有重要意义。 ... [详细]
  • 如何在 IntelliJ IDEA 中高效搭建和运行 Spring Boot 项目
    本文详细介绍了如何在 IntelliJ IDEA 中高效搭建和运行 Spring Boot 项目,涵盖了项目创建、配置及常见问题的解决方案。通过本指南,开发者可以快速掌握在 IntelliJ IDEA 中进行 Spring Boot 开发的最佳实践,提高开发效率。 ... [详细]
  • 在基于.NET框架的分层架构实践中,为了实现各层之间的松散耦合,本文详细探讨了依赖注入(DI)和控制反转(IoC)容器的设计与实现。通过合理的依赖管理和对象创建,确保了各层之间的单向调用关系,从而提高了系统的可维护性和扩展性。此外,文章还介绍了几种常见的IoC容器实现方式及其应用场景,为开发者提供了实用的参考。 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • 在Spring与Ibatis集成的环境中,通过Spring AOP配置事务管理至服务层。当在一个服务方法中引入自定义多线程时,发现事务管理功能失效。若不使用多线程,事务管理则能正常工作。本文深入分析了这一现象背后的潜在风险,并探讨了可能的解决方案,以确保事务一致性和线程安全。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • 深入解析Gradle中的Project核心组件
    在Gradle构建系统中,`Project` 是一个核心组件,扮演着至关重要的角色。通过使用 `./gradlew projects` 命令,可以清晰地列出当前项目结构中包含的所有子项目,这有助于开发者更好地理解和管理复杂的多模块项目。此外,`Project` 对象还提供了丰富的配置选项和生命周期管理功能,使得构建过程更加灵活高效。 ... [详细]
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
  • 如何在Java中高效构建WebService
    本文介绍了如何利用XFire框架在Java中高效构建WebService。XFire是一个轻量级、高性能的Java SOAP框架,能够简化WebService的开发流程。通过结合MyEclipse集成开发环境,开发者可以更便捷地进行项目配置和代码编写,从而提高开发效率。此外,文章还详细探讨了XFire的关键特性和最佳实践,为读者提供了实用的参考。 ... [详细]
  • IIS配置大全:从基础到高级的全面指南
    IIS配置详解:从基础到高级的全面指南IIS前端配置与web.config文件紧密相关,相互影响。本文详细介绍了如何设置允许通过的HTTP请求方法,包括HEAD、POST、GET、TRACE和OPTIONS。提供了两种主要的配置方法,并探讨了它们在实际应用中的优缺点。此外,还深入讲解了其他高级配置选项,帮助读者全面提升IIS服务器的性能和安全性。 ... [详细]
  • PHP连接MySQL的三种方法及预处理语句防止SQL注入的技术详解
    PHP连接MySQL的三种方法及预处理语句防止SQL注入的技术详解 ... [详细]
  • 深入解析Wget CVE-2016-4971漏洞的利用方法与安全防范措施
    ### 摘要Wget 是一个广泛使用的命令行工具,用于从 Web 服务器下载文件。CVE-2016-4971 漏洞涉及 Wget 在处理特定 HTTP 响应头时的缺陷,可能导致远程代码执行。本文详细分析了该漏洞的成因、利用方法以及相应的安全防范措施,包括更新 Wget 版本、配置防火墙规则和使用安全的 HTTP 头。通过这些措施,可以有效防止潜在的安全威胁。 ... [详细]
  • HTML5大文件传输技术深度解析与实践分享
    本文深入探讨了HTML5在Web前端开发中实现大文件上传的技术细节与实践方法。通过实例分析,详细讲解了如何利用HTML5的相关特性高效、稳定地处理大文件传输问题,并提供了可供参考的代码示例和解决方案。此外,文章还讨论了常见的技术挑战及优化策略,旨在帮助开发者更好地理解和应用HTML5大文件上传技术。 ... [详细]
author-avatar
凝笙儿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有