iris请求注入流程浅析,(非常详细)从零基础到精通,收藏这篇就够了!

.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

目前使用的是iris v1.12.0-alpha2,可以自动解析RequestBody成对象注入到参数中

iris的注入分成两个部分:
  • 依赖源列表准备

全局依赖是通过 mvcApp.Register(dependencies ...interface{}) 注入的,全局依赖在注册的时候只是保存依赖列表,接收到请求以后才进行注入

注册流程:

513602390.png

  • 请求时注入依赖

包括 iris.Context 在内的单个请求范围内的数据,mvcApp.Register() 如果是传入函数的,会在接收请求到请求以后再执行函数进行注入

依赖注入是在接收到请求的时候开始执行的,跟踪依赖注入要从请求处开始看

597581593.png

请求过程
  • 收到请求进行处理

core.router.router.go.Router.buildMainHandlerWithFilters()#router.mainHandler


    router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
        ctx := cPool.Acquire(w, r)
        filterExecuted := false
        for _, f := range sortedFilters { // from subdomain, largest path to shortest.
            // fmt.Printf("Sorted filter execution: [%s] [%s]\n", f.Subdomain, f.Path)

            // 匹配路由
            if f.Matcher.Match(ctx) {
                // fmt.Printf("Matched [%s] and execute [%d] handlers [%s]\n\n", ctx.Path(), len(f.Handlers), context.HandlersNames(f.Handlers))
                filterExecuted = true
                // execute the final handlers chain.
                ctx.Do(f.Handlers)
                break // and break on first found.
            }
        }

        // 没有匹配的路由,进
        if !filterExecuted {
            // If not at least one match filter found and executed,
            // then just run the router.
            router.requestHandler.HandleRequest(ctx)
        }

        // 释放iris上下文 
        cPool.Release(ctx)
    }


路由匹配会调用默认的

router.api_builder.go.defaultPartyMatcher


func defaultPartyMatcher(ctx *context.Context, p Party) bool {
    subdomain, path := splitSubdomainAndPath(p.GetRelPath())

    // 变量前的路径,eg: /users/{uid} 得到/users
    staticPath := staticPath(path)
    hosts := subdomain != ""
    if p.IsRoot() {
        // ALWAYS executed first when registered
        // through an `Application.UseRouter` call.
        return true
    }
    if hosts {
        // Note(@kataras): do NOT try to implement something like party matcher for each party
        // separately. We will introduce a new problem with subdomain inside a subdomain:
        // they are not by prefix, so parenting calls will not help
        // e.g. admin. and control.admin, control.admin is a sub of the admin.
        if !canHandleSubdomain(ctx, subdomain) {
            return false
        }
    }
    // this is the longest static path.
    return strings.HasPrefix(ctx.Path(), staticPath)
}


这里可以看出,仅匹配路径不匹配方法,方法将在后面对请求进行操作的时候判断

匹配到路由之后,iris上下文开始调用中件间

context.context.go.Context.Do

// Do sets the "handlers" as the chain
// and executes the first handler,
// handlers should not be empty.
//
// It's used by the router, developers may use that
// to replace and execute handlers immediately.
func (ctx *Context) Do(handlers Handlers) {
    if len(handlers) == 0 {
        return
    }
    ctx.handlers = handlers
    handlers[0](ctx)
}


这个方法比较简单,就是从第一个开始调用中间件,之后就是中间件自行遍历调用

context.context.go.Context.Next

// Next calls the next handler from the handlers chain,
// it should be used inside a middleware.
func (ctx *Context) Next() {
 if ctx.IsStopped() {
  return
 }

 nextIndex := ctx.currentHandlerIndex + 1
 handlers := ctx.handlers

 if n := len(handlers); nextIndex == n {
  atomic.StoreUint32(&ctx.proceeded, 1) // last handler but Next is called.
 } else if nextIndex < n {
  ctx.currentHandlerIndex = nextIndex
  handlers[nextIndex](ctx)

 }
}


如果有下一个则执行,没有下一步,那活也干完了,不管是全局中间件还是单个请求中间件都是这两个方法的形式在触发链式调用,从单个请求实际上也是以一个handler形式存在于这个链的底部,即为 Router.buildMainHandlerWithFilters.Handlers

请求上下文调用

core.router.router.go.Router.buildMainHandlerWithFilters#f.handlers


        f.Handlers = append(f.Handlers, func(ctx *context.Context) {

            // 上下文是复用的,数据需要重置
            // set the handler index back to 0 so the route's handlers can be executed as expected.
            ctx.HandlerIndex(0)
            // execute the main request handler, this will fire the found route's handlers
            // or if error the error code's associated handler.
            router.requestHandler.HandleRequest(ctx)
        })


router.requestHandler.HandleRequest便是单个请求的起点,iris在这里判断路由是否完全符合,方法是否正确

core.router.handler.go.routerHandler.HandlerRequest


func (h *routerHandler) HandleRequest(ctx *context.Context) {
    method := ctx.Method()
    path := ctx.Path()
    config := h.config // ctx.Application().GetConfigurationReadOnly()
    if !config.GetDisablePathCorrection() {
        ... 禁用路径校正,重定向等代码省略
    }

    // 再次匹配路由,此时的匹配会从最近的party开始,并且会对参数进行判断
    for i := range h.trees {
        t := h.trees[i]
        if method != t.method {
            continue
        }
        if h.hosts && !canHandleSubdomain(ctx, t.subdomain) {
            continue
        }

        // 带参数的路径判断,路由树的遍历
        n := t.search(path, ctx.Params())
        if n != nil {
            ctx.SetCurrentRoute(n.Route)
            ctx.Do(n.Handlers)
            // found
            return
        }
        // not found or method not allowed.
        break
    }

    ... 404 或其他重定向的处理

    ctx.StatusCode(http.StatusNotFound)
}


单个请求还是要跑自己的中间件,通常jwt、casbin等会在这里调用

单个请求的中间件链第一个跟最后一个比较特殊,第一个略过看最后一个,依赖的注入和请求结果将在这里进行分发

hero.handler.go.makeHandler#Func2

 return func(ctx *context.Context) {
  inputs := make([]reflect.Value, numIn)

  // bindings是在iris.Application初始化的时候就已经准备好了,handler在注册到iris.Application的时候通过getBindingsForFunc初始化了
  for _, binding := range bindings {
   input, err := binding.Dependency.Handle(ctx, binding.Input)
   if err != nil {
    if err == ErrSeeOther {
     continue
    }

    c.GetErrorHandler(ctx).HandleError(ctx, err)
    
    // return [13 Sep 2020, commented that in order to be able to
    // give end-developer the option not only to handle the error
    // but to skip it if necessary, example:
    // read form, unknown field, continue without StopWith,
    // the binder should bind the method's input argument and continue
    // without errors. See `mvc.TestErrorHandlerContinue` test.]
   }

   // If ~an error status code is set or~ execution has stopped
   // from within the dependency (something went wrong while validating the request),
   // then stop everything and let handler fire that status code.
   if ctx.IsStopped() {
    return
   }

   inputs[binding.Input.Index] = input
  }

  // 调用controller的业务逻辑
  outputs := v.Call(inputs)
  // 请求结果分发处理
  if err := dispatchFuncResult(ctx, outputs, resultHandler); err != nil {
   c.GetErrorHandler(ctx).HandleError(ctx, err)
  }
 }

篇头说过,注入模块有两部分,一部分是一开始的初始化,一部分是请求处理时的注入,这里的是注入。 Register的东西都被封装成Dependency,而注入是Dependency.Handle的执行,最终的注入有两种: 实例对象和函数注入

通过函数注入

hero.dependency.go.fromDependencyFunc

 handler := func(ctx *context.Context, _ *Input) (reflect.Value, error) {
  inputs := make([]reflect.Value, numIn)

  // 函数入参的处理
  for _, binding := range bindings {
   // 每个注入里面所需要的参数依然还是注入对象,直到不需要从外面传参数或者是静态注入
   input, err := binding.Dependency.Handle(ctx, binding.Input)
   if err != nil {
    if err == ErrSeeOther {
     continue
    }

    return emptyValue, err
   }

   inputs[binding.Input.Index] = input
  }

  // 调用函数
  outputs := v.Call(inputs)
  if firstOutIsError {
   return emptyValue, toError(outputs[0])
  } else if secondOutIsError {
   return outputs[0], toError(outputs[1])
  }

  // 从这里可以看出,Register的函数允许两个参数,一个是返回值,一个是error,返回值也就是我们要注入的对象,
  return outputs[0], nil
 }

这里会递归 Dependency.Handle 以便使每个函数的参数都能得到正确的入参,但这里也可以得到一个结论是 mvcApp.Register(func (val B) A) mvcApp.Register(func (val A) B) 这是不允许的,但如果真的进行了这样的操作会发生什么事情?第一个注入函数由于B没有在它的注入列表中,也没地方生成,所以它需要从用户的RequestBody中获取,为什么会这样需要去看一下iris初始化handler注入源列表是怎样做的

静态注入的获取比较简单,因为经过了封装了,于是只有一行代码:

hero.dependency.go.fromStructValue

  handler := func(*context.Context, *Input) (reflect.Value, error) {
   return v, nil
  }


RequestBody注入

hero.binding.go.payloadBinding

Handle: func(ctx *context.Context, input *Input) (newValue reflect.Value, err error) {
    wasPtr := input.Type.Kind() == reflect.Ptr

    if serveDepsV := ctx.Values().Get(context.DependenciesContextKey); serveDepsV != nil {
     if serveDeps, ok := serveDepsV.(context.DependenciesMap); ok {
      if newValue, ok = serveDeps[typ]; ok {
       return
      }
     }
    }

    if input.Type.Kind() == reflect.Slice {
     newValue = reflect.New(reflect.SliceOf(indirectType(input.Type)))
    } else {
     newValue = reflect.New(indirectType(input.Type))
    }

    ptr := newValue.Interface()
    err = ctx.ReadBody(ptr)
    if !wasPtr {
     newValue = newValue.Elem()
    }

    return
   }


经过handler的循环和递归,对函数的注入就完成了。但此时心中有个疑惑是 Controller 的属性又是在什么时候被赋值的?

再次调试发现,注入的列表中会对Controller进行注入,是bindings的一份子(第1个),对它的处理是在struct中

对controller的处理

hero.struct.go.Struct.Acquire


// Acquire returns a struct value based on the request.
// If the dependencies are all static then these are already set-ed at the initialization of this Struct
// and the same struct value instance will be returned, ignoring the Context. Otherwise
// a new struct value with filled fields by its pre-calculated bindings will be returned instead.
func (s *Struct) Acquire(ctx *context.Context) (reflect.Value, error) {
 if s.Singleton {
  ctx.Values().Set(context.ControllerContextKey, s.ptrValue)
  return s.ptrValue, nil
 }

 ctrl := ctx.Controller()
 if ctrl.Kind() == reflect.Invalid ||
  ctrl.Type() != s.ptrType /* in case of changing controller in the same request (see RouteOverlap feature) */ {
  ctrl = reflect.New(s.elementType)
  ctx.Values().Set(context.ControllerContextKey, ctrl)
  elem := ctrl.Elem()
  for _, b := range s.bindings {
   input, err := b.Dependency.Handle(ctx, b.Input)
   if err != nil {
    if err == ErrSeeOther {
     continue
    }

    s.Container.GetErrorHandler(ctx).HandleError(ctx, err)

    if ctx.IsStopped() {
     // return emptyValue, err
     return ctrl, err
    } // #1629
   }

   // 注入数据到struct
   elem.FieldByIndex(b.Input.StructFieldIndex).Set(input)
  }
 }

 return ctrl, nil
}


至此已经完成了注入了,但是对于注入很重要的bindings又是如何初始化的?

依赖源列表准备
mvcApp.Register方法内的的NewDependency

hero.dependency.NewDependency


// NewDependency converts a function or a function which accepts other dependencies or static struct value to a *Dependency.
//
// See `Container.Handler` for more.
func NewDependency(dependency interface{}, funcDependencies ...*Dependency) *Dependency {
    if dependency == nil {
        panic(fmt.Sprintf("bad value: nil: %T", dependency))
    }
    if d, ok := dependency.(*Dependency); ok {
        // already a *Dependency.
        return d
    }
    v := valueOf(dependency)
    if !goodVal(v) {
        panic(fmt.Sprintf("bad value: %#+v", dependency))
    }
    dest := &Dependency{
        Source: newSource(v),
        OriginalValue: dependency,
    }
    if !resolveDependency(v, dest, funcDependencies...) {
        panic(fmt.Sprintf("bad value: could not resolve a dependency from: %#+v", dependency))
    }
    return dest
}

func resolveDependency(v reflect.Value, dest *Dependency, funcDependencies ...*Dependency) bool {
 return fromDependencyHandler(v, dest) ||    // 本来就是DependencyHandler的拷贝封装
  fromStructValue(v, dest) ||    // 静态注入
  fromFunc(v, dest) ||    // 函数注入,第一个入参是context,且入参为1或2个
  len(funcDependencies) > 0 && fromDependentFunc(v, dest, funcDependencies) // 函数注入
}


binding的获取

不管是func还是struct,除了自身的逻辑,还会调用这个函数来获取到他所需要的bindings

hero.binding.go.getBindingsFor


func getBindingsFor(inputs []reflect.Type, deps []*Dependency, paramsCount int) (bindings []*binding) {
 // Path parameter start index is the result of [total path parameters] - [total func path parameters inputs],
 // moving from last to first path parameters and first to last (probably) available input args.
 //
 // That way the above will work as expected:
 // 1. mvc.New(app.Party("/path/{firstparam}")).Handle(....Controller.GetBy(secondparam string))
 // 2. mvc.New(app.Party("/path/{firstparam}/{secondparam}")).Handle(...Controller.GetBy(firstparam, secondparam string))
 // 3. usersRouter := app.Party("/users/{id:uint64}"); usersRouter.ConfigureContainer().Handle(method, "/", handler(id uint64))
 // 4. usersRouter.Party("/friends").ConfigureContainer().Handle(method, "/{friendID:uint64}", handler(friendID uint64))
 //
 // Therefore, count the inputs that can be path parameters first.
 shouldBindParams := make(map[int]struct{})
 totalParamsExpected := 0
 if paramsCount != -1 {
  for i, in := range inputs {
   if _, canBePathParameter := context.ParamResolvers[in]; !canBePathParameter {
    continue
   }
   shouldBindParams[i] = struct{}{}

   totalParamsExpected++
  }
 }

 startParamIndex := paramsCount - totalParamsExpected
 if startParamIndex < 0 {
  startParamIndex = 0
 }

 lastParamIndex := startParamIndex

 getParamIndex := func() int {
  paramIndex := lastParamIndex
  lastParamIndex++
  return paramIndex
 }

 bindedInput := make(map[int]struct{})

 for i, in := range inputs { //order matters.
  _, canBePathParameter := shouldBindParams[i]

  prevN := len(bindings) // to check if a new binding is attached; a dependency was matched (see below).

  for j := len(deps) - 1; j >= 0; j-- {
   d := deps[j]
   // Note: we could use the same slice to return.
   //
   // Add all dynamic dependencies (caller-selecting) and the exact typed dependencies.
   //
   // A dependency can only be matched to 1 value, and 1 value has a single dependency
   // (e.g. to avoid conflicting path parameters of the same type).
   if _, alreadyBinded := bindedInput[j]; alreadyBinded {
    continue
   }

   match := matchDependency(d, in)
   if !match {
    continue
   }

   if canBePathParameter {
    // wrap the existing dependency handler.
    paramHandler := paramDependencyHandler(getParamIndex())
    prevHandler := d.Handle
    d.Handle = func(ctx *context.Context, input *Input) (reflect.Value, error) {
     v, err := paramHandler(ctx, input)
     if err != nil {
      v, err = prevHandler(ctx, input)
     }

     return v, err
    }
    d.Static = false
    d.OriginalValue = nil
   }

   bindings = append(bindings, &binding{
    Dependency: d,
    Input: newInput(in, i, nil),
   })

   if !d.Explicit { // if explicit then it can be binded to more than one input
    bindedInput[j] = struct{}{}
   }

   break
  }

  // 遍历了所有的传进来的依赖源都无法找到对应的依赖源,判断为需要解析
  if prevN == len(bindings) {
   // int string等基础类型可以为path参数,优先进行判断
   if canBePathParameter {
    // no new dependency added for this input,
    // let's check for path parameters.
    bindings = append(bindings, paramBinding(i, getParamIndex(), in))
    continue
   }

   // 都不是就从RequestBody获取
   // else add builtin bindings that may be registered by user too, but they didn't.
   if isPayloadType(in) {
    bindings = append(bindings, payloadBinding(i, in))
    continue
   }
  }
 }

 return
}


Controller中路由的解析

application.Handler -> application.handler -> c := newControllerActivator -> c.activite() -> c.parseMethods(); c.parseHTTPErrorHandler() -> parseMethod -> ControllerActivitor.Handle

mvc.mvc.go.Application.handle

func (app *Application) handle(controller interface{}, options ...Option) *ControllerActivator {
 // initialize the controller's activator, nothing too magical so far.
  // 这里会保存下controller的一些信息,请求来的时候可以利用这些信息反射生成controller对象
 c := newControllerActivator(app, controller)

 // check the controller's "BeforeActivation" or/and "AfterActivation" method(s) between the `activate`
 // call, which is simply parses the controller's methods, end-dev can register custom controller's methods
 // by using the BeforeActivation's (a ControllerActivation) `.Handle` method.
 if before, ok := controller.(interface {
  BeforeActivation(BeforeActivation)
 }); ok {
  before.BeforeActivation(c)
 }

 for _, opt := range options {
  if opt != nil {
   opt.Apply(c)
  }
 }

 // 解析路由,注册到iris.app中,这时候会生成新的router
 c.activate()

 if after, okAfter := controller.(interface {
  AfterActivation(AfterActivation)
 }); okAfter {
  after.AfterActivation(c)
 }

  //  添加到 mvcApplication的Controllers列表
 app.Controllers = append(app.Controllers, c)
 return c
}


iris初始化和请求:

595049671.png

小结
  1. iris mvc对Party进行封装,往Party调用Handler()注册Controller的时候会被转换APIBuilder,生成Router列表,每个Router会包含有其路径信息、controller、上级信息、中间件等
  2. 调用 app.Listen 的时候将iris对APIBuilder进行处理,router的一些信息会得到补充(如mainHandler),iris.New()的时候生成的Router做为树的顶点,将会被设置成请求到来时的处理服务
  3. 请求到来的时候,从根Router开始进行匹配找到最能符合路径的Router,Router再进行处理,到业务逻辑前还会再进行一次路径匹配和请求方式匹配来找到最终的业务逻辑处理器
  4. 依赖注入的依赖源是一个有序列表,后面注册的依赖可以引用之前注册的依赖,但不能引用之后注册的依赖,当引用尚未注册的依赖可能会导致空指针或请求解析异常
  5. iris最核心的应该是中间件,在iris的请求处理中,都是通过不同的中间件完成,包括依赖注入、参数解析、请求处理等

黑客/网络安全学习路线

对于从来没有接触过黑客/网络安全的同学,目前网络安全、信息安全也是计算机大学生毕业薪资相对较高的学科。

大白也帮大家准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

这也是耗费了大白近四个月的时间,吐血整理,文章非常非常长,觉得有用的话,希望粉丝朋友帮忙点个**「分享」「收藏」「在看」「赞」**

网络安全/渗透测试法律法规必知必会****

今天大白就帮想学黑客/网络安全技术的朋友们入门必须先了解法律法律。

【网络安全零基础入门必知必会】网络安全行业分析报告(01)

【网络安全零基础入门必知必会】什么是黑客、白客、红客、极客、脚本小子?(02)

【网络安全零基础入门必知必会】网络安全市场分类(03)

【网络安全零基础入门必知必会】常见的网站攻击方式(04)

【网络安全零基础入门必知必会】网络安全专业术语全面解析(05)

【网络安全入门必知必会】《中华人民共和国网络安全法》(06)

【网络安全零基础入门必知必会】《计算机信息系统安全保护条例》(07)

【网络安全零基础入门必知必会】《中国计算机信息网络国际联网管理暂行规定》(08)

【网络安全零基础入门必知必会】《计算机信息网络国际互联网安全保护管理办法》(09)

【网络安全零基础入门必知必会】《互联网信息服务管理办法》(10)

【网络安全零基础入门必知必会】《计算机信息系统安全专用产品检测和销售许可证管理办法》(11)

【网络安全零基础入门必知必会】《通信网络安全防护管理办法》(12)

【网络安全零基础入门必知必会】《中华人民共和国国家安全法》(13)

【网络安全零基础入门必知必会】《中华人民共和国数据安全法》(14)

【网络安全零基础入门必知必会】《中华人民共和国个人信息保护法》(15)

【网络安全零基础入门必知必会】《网络产品安全漏洞管理规定》(16)

网络安全/渗透测试linux入门必知必会

【网络安全零基础入门必知必会】什么是Linux?Linux系统的组成与版本?什么是命令(01)

【网络安全零基础入门必知必会】VMware下载安装,使用VMware新建虚拟机,远程管理工具(02)

【网络安全零基础入门必知必会】VMware常用操作指南(非常详细)零基础入门到精通,收藏这一篇就够了(03)

【网络安全零基础入门必知必会】CentOS7安装流程步骤教程(非常详细)零基入门到精通,收藏这一篇就够了(04)

【网络安全零基础入门必知必会】Linux系统目录结构详细介绍(05)

【网络安全零基础入门必知必会】Linux 命令大全(非常详细)零基础入门到精通,收藏这一篇就够了(06)

【网络安全零基础入门必知必会】linux安全加固(非常详细)零基础入门到精通,收藏这一篇就够了(07)

网络安全/渗透测试****计算机网络入门必知必会****

【网络安全零基础入门必知必会】TCP/IP协议深入解析(非常详细)零基础入门到精通,收藏这一篇就够了(01)

【网络安全零基础入门必知必会】什么是HTTP数据包&Http数据包分析(非常详细)零基础入门到精通,收藏这一篇就够了(02)

【网络安全零基础入门必知必会】计算机网络—子网划分、子网掩码和网关(非常详细)零基础入门到精通,收藏这一篇就够了(03)

网络安全/渗透测试入门之HTML入门必知必会

【网络安全零基础入门必知必会】什么是HTML&HTML基本结构&HTML基本使用(非常详细)零基础入门到精通,收藏这一篇就够了1

【网络安全零基础入门必知必会】VScode、PhpStorm的安装使用、Php的环境配置,零基础入门到精通,收藏这一篇就够了2

【网络安全零基础入门必知必会】HTML之编写登录和文件上传(非常详细)零基础入门到精通,收藏这一篇就够了3

网络安全/渗透测试入门之Javascript入门必知必会

【网络安全零基础入门必知必会】Javascript语法基础(非常详细)零基础入门到精通,收藏这一篇就够了(01)

【网络安全零基础入门必知必会】Javascript实现Post请求、Ajax请求、输出数据到页面、实现前进后退、文件上传(02)

网络安全/渗透测试入门之Shell入门必知必会

【网络安全零基础入门必知必会】Shell编程基础入门(非常详细)零基础入门到精通,收藏这一篇就够了(第七章)

网络安全/渗透测试入门之PHP入门必知必会

【网络安全零基础入门】PHP环境搭建、安装Apache、安装与配置MySQL(非常详细)零基础入门到精通,收藏这一篇就够(01)

【网络安全零基础入门】PHP基础语法(非常详细)零基础入门到精通,收藏这一篇就够了(02)

【网络安全零基础入门必知必会】PHP+Bootstrap实现表单校验功能、PHP+MYSQL实现简单的用户注册登录功能(03)

网络安全/渗透测试入门之MySQL入门必知必会

【网络安全零基础入门必知必会】MySQL数据库基础知识/安装(非常详细)零基础入门到精通,收藏这一篇就够了(01)

【网络安全零基础入门必知必会】SQL语言入门(非常详细)零基础入门到精通,收藏这一篇就够了(02)

【网络安全零基础入门必知必会】MySQL函数使用大全(非常详细)零基础入门到精通,收藏这一篇就够了(03)

【网络安全零基础入门必知必会】MySQL多表查询语法(非常详细)零基础入门到精通,收藏这一篇就够了(04)

****网络安全/渗透测试入门之Python入门必知必会

【网络安全零基础入门必知必会】之Python+Pycharm安装保姆级教程,Python环境配置使用指南,收藏这一篇就够了【1】

【网络安全零基础入门必知必会】之Python编程入门教程(非常详细)零基础入门到精通,收藏这一篇就够了(2)

python开发之手写第一个python程序

python开发笔记之变量

python基础语法特征

python开发数据类型

python开发笔记之程序交互

python入门教程之python开发学习笔记基本数据类型

python入门教程之python开发笔记之格式化输出

python入门教程之python开发笔记基本运算符

python入门教程python开发基本流程控制if … else

python入门教程之python开发笔记流程控制之循环

python入门之Pycharm开发工具的使用

python入门教程之python字符编码转换

python入门之python开发字符编码

python入门之python开发基本数据类型数字

python入门python开发基本数据类型字符串

python入门python开发基本数据类型列表

python入门python开发基本数据类型

python入门教程之python开发可变和不可变数据类型和hash

python入门教程python开发字典数据类型

python入门之python开发笔记基本数据类型集合

python开发之collections模块

python开发笔记之三元运算

【网络安全零基础入门必知必会】之10个python爬虫入门实例(非常详细)零基础入门到精通,收藏这一篇就够了(3)

****网络安全/渗透测试入门之SQL注入入门必知必会

【网络安全渗透测试零基础入门必知必会】之初识SQL注入(非常详细)零基础入门到精通,收藏这一篇就够了(1)

【网络安全渗透测试零基础入门必知必会】之SQL手工注入基础语法&工具介绍(2)

【网络安全渗透测试零基础入门必知必会】之SQL注入实战(非常详细)零基础入门到精通,收藏这一篇就够了(3)

【网络安全渗透测试零基础入门必知必会】之SQLmap安装&实战(非常详细)零基础入门到精通,收藏这一篇就够了(4)

【网络安全渗透测试零基础入门必知必会】之SQL防御(非常详细)零基础入门到精通,收藏这一篇就够了(4)

****网络安全/渗透测试入门之XSS攻击入门必知必会

【网络安全渗透测试零基础入门必知必会】之XSS攻击基本概念和原理介绍(非常详细)零基础入门到精通,收藏这一篇就够了(1)

网络安全渗透测试零基础入门必知必会】之XSS攻击获取用户cookie和用户密码(实战演示)零基础入门到精通收藏这一篇就够了(2)

【网络安全渗透测试零基础入门必知必会】之XSS攻击获取键盘记录(实战演示)零基础入门到精通收藏这一篇就够了(3)

【网络安全渗透测试零基础入门必知必会】之xss-platform平台的入门搭建(非常详细)零基础入门到精通,收藏这一篇就够了4

【网络安全渗透测试入门】之XSS漏洞检测、利用和防御机制XSS游戏(非常详细)零基础入门到精通,收藏这一篇就够了5

****网络安全/渗透测试入门文件上传攻击与防御入门必知必会

【网络安全渗透测试零基础入门必知必会】之什么是文件包含漏洞&分类(非常详细)零基础入门到精通,收藏这一篇就够了1

【网络安全渗透测试零基础入门必知必会】之cve实际漏洞案例解析(非常详细)零基础入门到精通, 收藏这一篇就够了2

【网络安全渗透测试零基础入门必知必会】之PHP伪协议精讲(文件包含漏洞)零基础入门到精通,收藏这一篇就够了3

【网络安全渗透测试零基础入门必知必会】之如何搭建 DVWA 靶场保姆级教程(非常详细)零基础入门到精通,收藏这一篇就够了4

【网络安全渗透测试零基础入门必知必会】之Web漏洞-文件包含漏洞超详细全解(附实例)5

【网络安全渗透测试零基础入门必知必会】之文件上传漏洞修复方案6

****网络安全/渗透测试入门CSRF渗透与防御必知必会

【网络安全渗透测试零基础入门必知必会】之CSRF漏洞概述和原理(非常详细)零基础入门到精通, 收藏这一篇就够了1

【网络安全渗透测试零基础入门必知必会】之CSRF攻击的危害&分类(非常详细)零基础入门到精通, 收藏这一篇就够了2

【网络安全渗透测试零基础入门必知必会】之XSS与CSRF的区别(非常详细)零基础入门到精通, 收藏这一篇就够了3

【网络安全渗透测试零基础入门必知必会】之CSRF漏洞挖掘与自动化工具(非常详细)零基础入门到精通,收藏这一篇就够了4

【网络安全渗透测试零基础入门必知必会】之CSRF请求伪造&Referer同源&置空&配合XSS&Token值校验&复用删除5

****网络安全/渗透测试入门SSRF渗透与防御必知必会

【网络安全渗透测试零基础入门必知必会】之SSRF漏洞概述及原理(非常详细)零基础入门到精通,收藏这一篇就够了 1

【网络安全渗透测试零基础入门必知必会】之SSRF相关函数和协议(非常详细)零基础入门到精通,收藏这一篇就够了2

【网络安全渗透测试零基础入门必知必会】之SSRF漏洞原理攻击与防御(非常详细)零基础入门到精通,收藏这一篇就够了3**
**

****网络安全/渗透测试入门XXE渗透与防御必知必会

【网络安全渗透测试零基础入门必知必会】之XML外部实体注入(非常详细)零基础入门到精通,收藏这一篇就够了1

网络安全渗透测试零基础入门必知必会】之XXE的攻击与危害(非常详细)零基础入门到精通,收藏这一篇就够了2

【网络安全渗透测试零基础入门必知必会】之XXE漏洞漏洞及利用方法解析(非常详细)零基础入门到精通,收藏这一篇就够了3

【网络安全渗透测试零基础入门必知必会】之微信XXE安全漏洞处理(非常详细)零基础入门到精通,收藏这一篇就够了4

****网络安全/渗透测试入门远程代码执行渗透与防御必知必会

【网络安全渗透测试零基础入门必知必会】之远程代码执行原理介绍(非常详细)零基础入门到精通,收藏这一篇就够了1

【网络安全零基础入门必知必会】之CVE-2021-4034漏洞原理解析(非常详细)零基础入门到精通,收藏这一篇就够了2

【网络安全零基础入门必知必会】之PHP远程命令执行与代码执行原理利用与常见绕过总结3

【网络安全零基础入门必知必会】之WEB安全渗透测试-pikachu&DVWA靶场搭建教程,零基础入门到精通,收藏这一篇就够了4

****网络安全/渗透测试入门反序列化渗透与防御必知必会

【网络安全零基础入门必知必会】之什么是PHP对象反序列化操作(非常详细)零基础入门到精通,收藏这一篇就够了1

【网络安全零基础渗透测试入门必知必会】之php反序列化漏洞原理解析、如何防御此漏洞?如何利用此漏洞?2

【网络安全渗透测试零基础入门必知必会】之Java 反序列化漏洞(非常详细)零基础入门到精通,收藏这一篇就够了3

【网络安全渗透测试零基础入门必知必会】之Java反序列化漏洞及实例解析(非常详细)零基础入门到精通,收藏这一篇就够了4

【网络安全渗透测试零基础入门必知必会】之CTF题目解析Java代码审计中的反序列化漏洞,以及其他漏洞的组合利用5

网络安全/渗透测试**入门逻辑漏洞必知必会**

【网络安全渗透测试零基础入门必知必会】之一文带你0基础挖到逻辑漏洞(非常详细)零基础入门到精通,收藏这一篇就够了

网络安全/渗透测试入门暴力猜解与防御必知必会

【网络安全渗透测试零基础入门必知必会】之密码安全概述(非常详细)零基础入门到精通,收藏这一篇就够了1

【网络安全渗透测试零基础入门必知必会】之什么样的密码是不安全的?(非常详细)零基础入门到精通,收藏这一篇就够了2

【网络安全渗透测试零基础入门必知必会】之密码猜解思路(非常详细)零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之利用Python暴力破解邻居家WiFi密码、压缩包密码,收藏这一篇就够了4

【网络安全渗透测试零基础入门必知必会】之BurpSuite密码爆破实例演示,零基础入门到精通,收藏这一篇就够了5

【网络安全渗透测试零基础入门必知必会】之Hydra密码爆破工具使用教程图文教程,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之暴力破解medusa,零基础入门到精通,收藏这一篇就够了7

【网络安全渗透测试零基础入门必知必会】之Metasploit抓取密码,零基础入门到精通,收藏这一篇就够了8

Wfuzz:功能强大的web漏洞挖掘工具

****网络安全/渗透测试入门掌握Redis未授权访问漏洞必知必会

【网络安全渗透测试零基础入门必知必会】之Redis未授权访问漏洞,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之Redis服务器被攻击后该如何安全加固,零基础入门到精通,收藏这一篇就够了**
**

网络安全/渗透测试入门掌握**ARP渗透与防御关必知必会**

【网络安全渗透测试零基础入门必知必会】之ARP攻击原理解析,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之ARP流量分析,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之ARP防御策略与实践指南,零基础入门到精通,收藏这一篇就够了

网络安全/渗透测试入门掌握系统权限提升渗透与防御关****必知必会

【网络安全渗透测试零基础入门必知必会】之Windows提权常用命令,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之Windows权限提升实战,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之linux 提权(非常详细)零基础入门到精通,收藏这一篇就够了

网络安全/渗透测试入门掌握Dos与DDos渗透与防御相关****必知必会

【网络安全渗透测试零基础入门必知必会】之DoS与DDoS攻击原理(非常详细)零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之Syn-Flood攻击原理解析(非常详细)零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之IP源地址欺骗与dos攻击,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之SNMP放大攻击原理及实战演示,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之NTP放大攻击原理,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之什么是CC攻击?CC攻击怎么防御?,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之如何防御DDOS的攻击?零基础入门到精通,收藏这一篇就够了

网络安全/渗透测试入门掌握无线网络安全渗透与防御相****必知必会

【网络安全渗透测试零基础入门必知必会】之Aircrack-ng详细使用安装教程,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之aircrack-ng破解wifi密码(非常详细)零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之WEB渗透近源攻击,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之无线渗透|Wi-Fi渗透思路,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之渗透WEP新思路Hirte原理解析,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之WPS的漏洞原理解析,零基础入门到精通,收藏这一篇就够了

网络安全/渗透测试入门掌握木马免杀问题与防御********必知必会

【网络安全渗透测试零基础入门必知必会】之Metasploit – 木马生成原理和方法,零基础入门到精通,收藏这篇就够了

【网络安全渗透测试零基础入门必知必会】之MSF使用教程永恒之蓝漏洞扫描与利用,收藏这一篇就够了

网络安全/渗透测试入门掌握Vulnhub靶场实战********必知必会

【网络安全渗透测试零基础入门必知必会】之Vulnhub靶机Prime使用指南,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之Vulnhub靶场Breach1.0解析,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之vulnhub靶场之DC-9,零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之Vulnhub靶机Kioptrix level-4 多种姿势渗透详解,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之Vulnhub靶场PWNOS: 2.0 多种渗透方法,收藏这一篇就够了

网络安全/渗透测试入门掌握社会工程学必知必会

【网络安全渗透测试零基础入门必知必会】之什么是社会工程学?定义、类型、攻击技术,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之社会工程学之香农-韦弗模式,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之社工学smcr通信模型,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之社会工程学之社工步骤整理(附相应工具下载)收藏这一篇就够了

网络安全/渗透测试入门掌握********渗透测试工具使用******必知必会**

2024版最新Kali Linux操作系统安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

【网络安全渗透测试零基础入门必知必会】之渗透测试工具大全之Nmap安装使用命令指南,零基础入门到精通,收藏这一篇就够了

2024版最新AWVS安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

2024版最新burpsuite安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

2024版最新owasp_zap安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

2024版最新Sqlmap安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

2024版最新Metasploit安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

2024版最新Nessus下载安装激活使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

2024版最新Wireshark安装使用教程(非常详细)零基础入门到精通,收藏这一篇就够了

觉得有用的话,希望粉丝朋友帮大白点个**「分享」「收藏」「在看」「赞」**

黑客/网络安全学习包

资料目录

  1. 成长路线图&学习规划

  2. 配套视频教程

  3. SRC&黑客文籍

  4. 护网行动资料

  5. 黑客必读书单

  6. 面试题合集

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

1.成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。


因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

2.视频教程

很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,其中一共有21个章节,每个章节都是当前板块的精华浓缩


因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

3.SRC&黑客文籍

大家最喜欢也是最关心的SRC技术文籍&黑客技术也有收录

SRC技术文籍:

黑客资料由于是敏感资源,这里不能直接展示哦!

4.护网行动资料

其中关于HW护网行动,也准备了对应的资料,这些内容可相当于比赛的金手指!

5.黑客必读书单

**

**

6.面试题合集

当你自学到这里,你就要开始思考找工作的事情了,而工作绕不开的就是真题和面试题。

更多内容为防止和谐,可以扫描获取~

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

****************************CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值