精华内容
下载资源
问答
  • SAFE-BookStore, 安全重新加载的安全堆栈项目的工作示例 为开发者的快乐设计一个网页栈设计下面的文档描述了安全堆栈示例项目。 安全是将若干技术集成到单一的。一致的栈中的技术堆栈,它们是一个面向对象的灵活的...
  • openssl的堆栈实现共涉及到三个文件,stack.h、stack.c 和safestack.h;其中stack.h、stack.c 实现了stack_st结构体,及对该结构体对象进行操作的一系列以OPENSSL_sk开头的函数,主要有:堆栈拷贝(OPENSSL_sk_dup)...

    读openssl的源码一直可以看到DEFINE_STACK_OF这个宏,它被定义在safestack.h这个头文件中。openssl的堆栈实现共涉及到三个文件,stack.h、stack.c 和safestack.h;其中stack.h、stack.c 实现了stack_st结构体,及对该结构体对象进行操作的一系列以OPENSSL_sk开头的函数,主要有:堆栈拷贝(OPENSSL_sk_dup)、构建新堆栈(OPENSSL_sk_new_null,OPENSSL_sk_new)、插入数据(OPENSSL_sk_insert)、删除数据(OPENSSL_sk_delete)、查找数据(OPENSSL_sk_find,OPENSSL_sk_find_ex)、入栈(OPENSSL_sk_push)、出栈(OPENSSL_sk_pop)、获取堆栈元素个数(OPENSSL_sk_num)、获取堆栈值(OPENSSL_sk_value)、设置堆栈值(OPENSSL_sk_set)和堆栈排序(OPENSSL_sk_sort)。

    比对openssl0.9.6版本,stack_st,被定义成STACK,

    typedef struct stack_st
    	{
    	int num;
    	char **data;
    	int sorted;
    
    	int num_alloc;
    	int (*comp)(const char * const *, const char * const *);
    	} STACK;

           而openssl1.1.0版本,该结构体声明在了stack.c文件中,且在stack.h中,typedef struct stack_st OPENSSL_STACK; /* Use STACK_OF(...) instead */  使得调用者对该结构体的具体成员不得操作,有点类的私有成员变量的意思在里边.

    safestack.h封装的提升使得SKM_DEFINE_STACK_OF(t1, t2, t3),出现了多态的样式,只要给该宏传入类型即可用他生成一套对该数据类型操作的函数来,而其本质还是转换为对OPENSSL_STACK 类型的操作。

    # define STACK_OF(type) struct stack_st_##type
    # define SKM_DEFINE_STACK_OF(t1, t2, t3) \
        STACK_OF(t1); \
        typedef int (*sk_##t1##_compfunc)(const t3 * const *a, const t3 *const *b); \
        typedef void (*sk_##t1##_freefunc)(t3 *a); \
        typedef t3 * (*sk_##t1##_copyfunc)(const t3 *a); \
        static ossl_inline int sk_##t1##_num(const STACK_OF(t1) *sk) \
        { \
            return OPENSSL_sk_num((const OPENSSL_STACK *)sk); \
        } \
        static ossl_inline t2 *sk_##t1##_value(const STACK_OF(t1) *sk, int idx) \
        { \
            return (t2 *)OPENSSL_sk_value((const OPENSSL_STACK *)sk, idx); \
        } \
        static ossl_inline STACK_OF(t1) *sk_##t1##_new(sk_##t1##_compfunc compare) \
        { \
            return (STACK_OF(t1) *)OPENSSL_sk_new((OPENSSL_sk_compfunc)compare); \
        } \
        static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \
        { \
            return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \
        } \
        static ossl_inline STACK_OF(t1) *sk_##t1##_new_reserve(sk_##t1##_compfunc compare, int n) \
        { \
            return (STACK_OF(t1) *)OPENSSL_sk_new_reserve((OPENSSL_sk_compfunc)compare, n); \
        } \
        static ossl_inline int sk_##t1##_reserve(STACK_OF(t1) *sk, int n) \
        { \
            return OPENSSL_sk_reserve((OPENSSL_STACK *)sk, n); \
        } \
        static ossl_inline void sk_##t1##_free(STACK_OF(t1) *sk) \
        { \
            OPENSSL_sk_free((OPENSSL_STACK *)sk); \
        } \
        static ossl_inline void sk_##t1##_zero(STACK_OF(t1) *sk) \
        { \
            OPENSSL_sk_zero((OPENSSL_STACK *)sk); \
        } \
        static ossl_inline t2 *sk_##t1##_delete(STACK_OF(t1) *sk, int i) \
        { \
            return (t2 *)OPENSSL_sk_delete((OPENSSL_STACK *)sk, i); \
        } \
        static ossl_inline t2 *sk_##t1##_delete_ptr(STACK_OF(t1) *sk, t2 *ptr) \
        { \
            return (t2 *)OPENSSL_sk_delete_ptr((OPENSSL_STACK *)sk, \
                                               (const void *)ptr); \
        } \
        static ossl_inline int sk_##t1##_push(STACK_OF(t1) *sk, t2 *ptr) \
        { \
            return OPENSSL_sk_push((OPENSSL_STACK *)sk, (const void *)ptr); \
        } \
        static ossl_inline int sk_##t1##_unshift(STACK_OF(t1) *sk, t2 *ptr) \
        { \
            return OPENSSL_sk_unshift((OPENSSL_STACK *)sk, (const void *)ptr); \
        } \
        static ossl_inline t2 *sk_##t1##_pop(STACK_OF(t1) *sk) \
        { \
            return (t2 *)OPENSSL_sk_pop((OPENSSL_STACK *)sk); \
        } \
        static ossl_inline t2 *sk_##t1##_shift(STACK_OF(t1) *sk) \
        { \
            return (t2 *)OPENSSL_sk_shift((OPENSSL_STACK *)sk); \
        } \
        static ossl_inline void sk_##t1##_pop_free(STACK_OF(t1) *sk, sk_##t1##_freefunc freefunc) \
        { \
            OPENSSL_sk_pop_free((OPENSSL_STACK *)sk, (OPENSSL_sk_freefunc)freefunc); \
        } \
        static ossl_inline int sk_##t1##_insert(STACK_OF(t1) *sk, t2 *ptr, int idx) \
        { \
            return OPENSSL_sk_insert((OPENSSL_STACK *)sk, (const void *)ptr, idx); \
        } \
        static ossl_inline t2 *sk_##t1##_set(STACK_OF(t1) *sk, int idx, t2 *ptr) \
        { \
            return (t2 *)OPENSSL_sk_set((OPENSSL_STACK *)sk, idx, (const void *)ptr); \
        } \
        static ossl_inline int sk_##t1##_find(STACK_OF(t1) *sk, t2 *ptr) \
        { \
            return OPENSSL_sk_find((OPENSSL_STACK *)sk, (const void *)ptr); \
        } \
        static ossl_inline int sk_##t1##_find_ex(STACK_OF(t1) *sk, t2 *ptr) \
        { \
            return OPENSSL_sk_find_ex((OPENSSL_STACK *)sk, (const void *)ptr); \
        } \
        static ossl_inline void sk_##t1##_sort(STACK_OF(t1) *sk) \
        { \
            OPENSSL_sk_sort((OPENSSL_STACK *)sk); \
        } \
        static ossl_inline int sk_##t1##_is_sorted(const STACK_OF(t1) *sk) \
        { \
            return OPENSSL_sk_is_sorted((const OPENSSL_STACK *)sk); \
        } \
        static ossl_inline STACK_OF(t1) * sk_##t1##_dup(const STACK_OF(t1) *sk) \
        { \
            return (STACK_OF(t1) *)OPENSSL_sk_dup((const OPENSSL_STACK *)sk); \
        } \
        static ossl_inline STACK_OF(t1) *sk_##t1##_deep_copy(const STACK_OF(t1) *sk, \
                                                        sk_##t1##_copyfunc copyfunc, \
                                                        sk_##t1##_freefunc freefunc) \
        { \
            return (STACK_OF(t1) *)OPENSSL_sk_deep_copy((const OPENSSL_STACK *)sk, \
                                                (OPENSSL_sk_copyfunc)copyfunc, \
                                                (OPENSSL_sk_freefunc)freefunc); \
        } \
        static ossl_inline sk_##t1##_compfunc sk_##t1##_set_cmp_func(STACK_OF(t1) *sk, sk_##t1##_compfunc compare) \
        { \
            return (sk_##t1##_compfunc)OPENSSL_sk_set_cmp_func((OPENSSL_STACK *)sk, (OPENSSL_sk_compfunc)compare); \
        }

    仔细阅读你会发现,STACK_OF(type) 只有对新类型结构体的声明而没有定义,与0.9.6版本的实现不同。如下

    #define STACK_OF(type) struct stack_st_##type
    #define PREDECLARE_STACK_OF(type) STACK_OF(type);
    
    #define DECLARE_STACK_OF(type) \
    STACK_OF(type) \
        { \
        STACK stack; \
        };   //0.9.6   STACK_OF(type) 结构的定义
    

    我在这块陷入了困境,而后请教前辈才渐渐悟到其中道理,此处只声明了结构体,在使用的时候,也仅只是定义了一个结构体对象的指针,也即结构体的入口地址,结构体中存储的成员,他并不直接去访问。而是通过宏里边实现的操作函数,把STACK_OF(type)转为stack_st类型,调用OPENSSL_STACK(和stack_st是一个)结构的操作函数去处理成员。STACK_OF(type)虽然没有定义成员,但它的对象有存放地址,该地址处存放的数据的类型,和stack_st成员的类型一模一样,操作的时候,只要按照stack_st的内存结构去读去写即可。

    至此其他人也可以利用宏define SKM_DEFINE_STACK_OF(t1, t2, t3)定义出对t1结构对象操作的一套API出来,我简单测试如下:

    #include "openssl/stack.h"
    #include "openssl/X509.h"
    
    struct TASK
    {
    	int ID;
    	std::string name;
    	std::string otherInfo;
    };
    
    DEFINE_STACK_OF(TASK)
    
    int compareFun(const TASK * const *first, const TASK *const *second)
    {
    	return (*first)->ID - (*second)->ID;
    }
    
    void freeTeskFun(TASK *task)
    {
    	delete task;
    }
    void taskStackTest()
    {
    	STACK_OF(TASK) *mytask = sk_TASK_new(compareFun);
    	TASK *t1=new TASK{1,std::string{"ssss"},std::string{"other1"}};
    	sk_TASK_push(mytask, t1);
    	TASK *t2 = new TASK{int(2),std::string{"two"},std::string{"twootherinfo"}};
    	sk_TASK_push(mytask, t2);
    
    	std::cout << sk_TASK_num(mytask) << std::endl;
    
    	TASK *popDT = static_cast<TASK *>(sk_TASK_pop(mytask));
    	std::cout << popDT->ID<<" "<< popDT->name << std::endl;
    	delete popDT;
    	//OPENSSL_STACK *ll = (OPENSSL_STACK *)mytask;
    	sk_TASK_pop_free(mytask,freeTeskFun);
    }

     

    展开全文
  • 最近为了实现一个集合,去了解了下安全集合,我一直以为ConcurrentStack和ConcurrentQueue应该内部差不多,因为他们功能差别不大。但是现在发现一个是数组,一个是链表,为啥会选择2类不同的结构来实现呢?是什么...
  • Palerra是一个云安全初创公司,由Oracle的校友Rohit Gupta (首席执行官)和Ganesh Kirti (首席技术官)共同创立。 交易的具体条款并未透露。Palerra最初成立于2013(原名Apprity),曾融资2500万美元,其中投资者...

    Oracle本周的大客户会谈在旧金山拉开序幕,为纪念此活动,公司宣布收购Palerra。Palerra是一个云安全初创公司,由Oracle的校友Rohit Gupta (首席执行官)和Ganesh Kirti (首席技术官)共同创立。

    交易的具体条款并未透露。Palerra最初成立于2013(原名Apprity),曾融资2500万美元,其中投资者包括Norwest Venture Partners和 August Capital。

    Palerra目前的业务主要是为企业应用程序提供安全自动化服务,该安全服务不仅涵盖了应用程序中的数据,而且正如我们去年所描述的一样,还涵盖“整个服务中的移动数据,以及跨基础设施和软件服务的多层数据保护”。由于现在很多应用程序都是通过API方式整合和交换数据,Palerra的这一业务显得格外重要。

    Gupta在博客中指出:该公司将继续为现有客户提供服务,同时也在为未来提供更多服务而努力。其客户包括Mware、Pitney Bowes 和Jefferies。公司也与微软这样的企业合作。

    当下企业面临的网络攻击比以往任何时候都要多,安全问题突出,因此alPerra的功能套装市场需求很大。其功能涵盖漏洞查找、合规性、内部威胁检测和事件响应。

    虽然Gupta和Oracle没有就新的产品规划透露更多细节性消息,但是Gupta指出,他们将与Oracle平台在集成业务上展开合作。

    他写道:“总之,Oracle收购Palerra将有助于通过提供全面的身份认证和安全的云服务加速云部署安全,Oracle的身份云服务和Palerra的CASB平台计划相结合,将为用户、应用程序、API、数据和基础设施提供全面的保护,以确保企业使用云计算和SaaS应用。”

    在他的博客中,Oracle的安全性和身份验证高级副总裁Peter Barker还补充说,这项解决方案将覆盖“用户、应用程序和API。”

    你会看到公司如何把它作为一个附加功能覆盖到自己的企业软件中,或者像今天一样作为独立的产品出售。

    至今Oracle已收购100多家企业或公司,但安全领域的收购并不多。其他收购有2005年的Oblix公司和2003年的设备管理初创公司Bitzer Mobile等。

    本文转自d1net(转载)

    展开全文
  • #include template, class T2> void construct(T1* p,const T2& val) ...3、异常安全性更强,在内存重分配过程中出现的异常,导致TOP等引用失效的情况将不复存在,属于commit-and-rollback级别的异常。
     
    

    #include <new>

    template<class T1, class T2>
    void construct(T1* p,const T2& val)
    {
     new (p) T1(val);
    }

    template <class T>
    void destroy(T* p)
    {
     p->~T();
    }

    template <class FwdIter>
    void destroy(FwdIter first,FwdIter last)
    {
     while (first != last)
     {
      destroy(&*first);
      ++first;
     }
    }

    template <class T>
    void swap(T& a,T& b)
    {
     T temp(a); a=b;b=temp;
    }

    template<class T>
    class StackImpl
    {
    protected:
     StackImpl(size_t size):
       v_(static_cast<T*>
        (size == 0 ? 0 :operator new (sizeof(T)*size))),
        vused_(0),
        vsize_(size)
     {}
     ~StackImpl()
     {
      destroy(v_,v_ + vused_);
      operator delete (v_);
     }
     void Swap(StackImpl& other) throw()
     {
      swap(v_,other.v_);
      swap(vsize_,other.vsize_);
      swap(vused_,other.vused_);
     }

     T* v_;
     size_t vsize_;
     size_t vused_;

    private:
     StackImpl(const StackImpl& other);
     StackImpl& operator=(const StackImpl& other);


    };

    template<class T>
    class Stack:private StackImpl<T>
    {
    public:
     Stack(size_t size=0):StackImpl<T>(size)
     {}

     Stack(const Stack& other):StackImp<T>(other.vused_)
     {
      while(vused_ < other.vused_)
      {
       construct(v_+vused_,other.v_[vused_]);
       ++vused_;
      }

     }

     Stack& operator=(const Stack& other)
     {
      Stack temp(other);
      Swap(temp);
      return *this;
     }

     ~Stack()
     {
     }

     bool Empty()
     {
      return 0 == vused_;
     }

     size_t Count()const
     {
      return vused_;
     }

     void Push(const T& t)
     {
      if(vused_ == vsize_)
      {
       Stack temp(2*vsize_ + 1);
       while(temp.Count() < vused_)
       {
        temp.Push(v_[temp.Count()]);
       }
       temp.Push(t);
       Swap(temp);
      }
      else
      {
       construct(v_+vused_,t);
       ++vused_;
      }

     }

     void Pop()
     {
      if (vused_ == 0)
      {
       throw "pop from empty stack";
      }
      else
      {
       --vused_;
       destroy(v_+vused_);
      }
     }

     T& Top()
     {
      if (vused_ == 0)
      {
       throw "empty stack";
      }
      return v_[vused_-1];
     }
    };

     

    说明:

    1、去掉了第一个版本中的try语句

    2、构造函数和拷贝构造函数及赋值函数更优雅。

    3、异常安全性更强,在内存重分配过程中出现的异常,导致TOP等引用失效的情况将不复存在,属于commit-and-rollback级别的异常。

    展开全文
  • 自动化ELK堆栈部署 该存储库中的文件用于配置以下所示的网络。 ![azure environment](Azure Environment.png) 这些文件已经过测试,并用于在Azure上生成实时ELK部署。 它们可用于重新创建上图所示的整个部署。 ...
  • 堆栈(Stack)代表了一个后进先出的对象集合。当您需要对各项进行后进先出的访问时,则使用堆栈。当您在列表中添加一项,称为推入元素,当您从列表中移除一项时,称为弹出元素。 Stack 类的方法和属性 Stack 类的...

    一、Stack
    堆栈(Stack)代表了一个后进先出的对象集合。当您需要对各项进行后进先出的访问时,则使用堆栈。当您在列表中添加一项,称为推入元素,当您从列表中移除一项时,称为弹出元素。

    Stack 类的方法和属性
    Stack 类的一些常用的 属性:

    属性 描述
    Count 获取 Stack 中包含的元素个数。

    Stack 类的一些常用的 方法:

    方法 描述
    public virtual void Clear(); 从 Stack 中移除所有的元素。
    public virtual bool Contains( object obj ); 判断某个元素是否在 Stack 中。
    public virtual object Peek(); 返回在 Stack 的顶部的对象,但不移除它。
    public virtual object Pop(); 移除并返回在 Stack 的顶部的对象。
    public virtual void Push( object obj ); 向 Stack 的顶部添加一个对象。
    public virtual object[] ToArray(); 复制 Stack 到一个新的数组中。

    实例

    using System;
    using System.Collections;
    
    namespace CollectionsApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                Stack st = new Stack();
    
                st.Push('A');
                st.Push('M');
                st.Push('G');
                st.Push('W');
               
                Console.WriteLine("Current stack: ");
                foreach (char c in st)
                {
                    Console.Write(c + " ");
                }
                Console.WriteLine();
               
                st.Push('V');
                st.Push('H');
                Console.WriteLine("The next poppable value in stack: {0}",
                st.Peek());
                Console.WriteLine("Current stack: ");          
                foreach (char c in st)
                {
                   Console.Write(c + " ");
                }
                Console.WriteLine();
    
                Console.WriteLine("Removing values :{0}", st.Pop());
                Console.WriteLine("Removing values :{0}", st.Pop());
                Console.WriteLine("Removing values :{0}", st.Pop());
               
                Console.WriteLine("Current stack: ");
                foreach (char c in st)
                {
                   Console.Write(c + " ");
                }
            }
        }
    }
    

    结果

    Current stack: 
    W G M A
    The next poppable value in stack: H
    Current stack: 
    H V W G M A
    Removing values :H
    Removing values :V
    Removing values :W
    Current stack: 
    G M A
    

    二、ConcurrentStack

    由于Stack是线程不安全的集合,在进行多线程多任务操作集合时会出现数据丢失等问题。通常的解决方法是添加lock锁。lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。但锁的引入,带来了一定的开销和性能的损耗,并降低了程序的扩展性,而且还会有死锁的可能。

    在.NET Framework 4提供了新的线程安全和扩展的并发集合,它们能够解决潜在的死锁问题和竞争条件问题,因此在很多复杂的情形下它们能够使得并行代码更容易编写,这些集合尽可能减少使用锁的次数,从而使得在大部分情形下能够优化为最佳性能,不会产生不必要的同步开销。(需要注意:在串行代码中不要使用并发集合,会增加不必要的开销)

    Stack对应的线程安全的并发集合就是 ConcurrentStack,命名空间:System.Collections.Concurrent
    ConcurrentStack类的常用方法:

    方法 描述
    public void Push(Object obj) 向 ConcurrentStack的顶部添加一个对象。
    public bool TryPop() 移除并返回在 ConcurrentStack的顶部的对象。

    关于ConcurrentStack是如何实现线程安全的,可参考文章C# ConcurrentStack实现

    展开全文
  • java 递归 堆栈 在本文中,摘自《 Java中的函数编程 》一书,我解释了如何使用递归,同时避免了StackOverflow异常的风险。 Corecursion正在使用第一步的输出作为下一步的输入来构成计算步骤。 递归是相同的操作,...
  • 堆栈

    2013-01-14 16:29:10
    所以堆栈段的安全余量设置,实际上是中断堆栈深度的配置。 3、如果不考虑系统堆栈安全余量设置,一个没有二级中断嵌套的一级中断堆栈深度应该是13字节。——为什么? 4、系统中断的安全余量配置应该是……字节。...
  • 强化TCP/IP堆栈安全

    2021-03-04 22:58:31
    可以在Windows注册表内配置各种TCP/IP参数,以便保护服务器免遭网络级别的拒绝服务攻击,包括SYS洪水攻击、ICMP攻击和SNMP攻击。...TCP/IP天生就是一个不安全的协议。但是,Windows2000版本允许您配
  • 安全入门之堆栈溢出

    2007-09-04 14:48:00
    今天接着写安全入门话题之堆栈溢出。 堆栈溢出简单说就是所定义数据结构存放在堆栈中,并且输入数据超过了定义数据的大小,覆盖了属于或者不属于堆栈的部分,通常会引起访问非法或者段错误。如果没有发现就成为了...
  • 为企业容器平台配备了安全的Kubernetes堆栈。 结合Docker Enterprise 3.0的发布,Docker还推出了Docker Enterprise的托管服务选项。 Docker Enterprise被定位为用于构建,运行和共享基于容器的应用程序的端到端...
  • Java中的堆栈安全递归

    2020-05-31 17:59:24
    } 现在,我们可以以更简单,更安全的方式获得递归调用的结果: add(3, 100000000).eval() 但这还不是我们想要的。 我们想要摆脱对eval方法的调用。 这可以通过一个辅助方法来完成: import static ...
  • 强化 TCP/IP 堆栈安全

    2017-08-17 09:25:25
    抵御 SYN ***SYN ***利用了 TCP/IP 连接建立机制中的安全漏洞。要实施 SYN 洪水***,***者会使用程序发送大量 TCP SYN 请求来填满服务器上的挂起连接队列。这会禁止其他用户建立网络连接。要保护网络抵御 SYN ***,...
  • 堆栈方面入手进行的网络攻防 分享加备份
  • 强化服务器的 TCP/IP 堆栈安全 • 保护服务器免遭“拒绝服务”和其他基于网络的攻击 • 在检测到攻击时启用 SYN 洪水攻击保护 • 设置用于确认是什么构成攻击的阈值 适用范围 本模块适用...
  • 再说一下线程安全,直接在堆栈中分配的局部变量当然是安全的,但是指针不安全,如果每条线程分配一个对象,这种面向对象也是安全的,全局变量是不安全的,而不同线程使用同一个对象也是不安全的。   ...
  • 2、线程安全堆栈类 标准库中的stack结构是非线程安全的,为什么这么说呢?考虑一下stack的pop方法和top方法,pop方法只是出栈操作,top方法是取栈顶元素,设想一下有两个线程A和B,对某一个公共stack进行操作,...
  • 按OSI分层角度探讨网络安全,深入研究OSI堆栈,从物理层开始直到应用层。从分析每一层的漏洞出发,假想攻击这些漏洞的各种可能性,在此基础上讨论各个网络层次的安全防御手段。在讨论了所有的技术环节后,并没有忘记...
  • 快速且类型安全的全堆栈框架,用于TypeScript 为什么要弗鲁里奥(frourio)? 即使您同时在TypeScript中编写前端和后端,也无法静态地对API的稀疏性进行类型检查。 我们总是被迫编写“ Two TypeScript”。 我们在...
  • 目标 使用本模块可以实现:• 强化服务器的 TCP/IP 堆栈安全• 保护服务器免遭“拒绝服务”和其他基于网络的攻击• 在检测到攻击时启用 SYN 洪水攻击保护• 设置用于确认是什么构成攻击的...
  • pureapp:一个小型库,用于编写参照透明且堆栈安全的顺序程序
  • holberton-system_engineering-devops
  • 此存储库包含的规范, 是模块化的对等消息传递堆栈,重点是安全消息传递。 有关vac及其设计目标的详细说明,请参见。 状态 整个vac协议正在积极开发中,每个规范都有其自己的status ,这可以通过每个文档顶部的版本...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,139
精华内容 855
关键字:

安全堆栈