子站间 携带cookie_Cookie知识点总结

概念

Cookie是服务端发送到用户浏览器并且保存到本地的一小块数据,它会在浏览器下次向同一服务器发起请求时,被携带到服务器上。

为什么有cookie

因为HTTP协议是无状态的(HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。),即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。 在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两瓶饮料。 最后结帐时,由于HTTP的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么。 所以Cookie就是用来绕开HTTP的无状态性的“额外手段”之一。 服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。 在刚才的购物场景中,当用户选购了第一项商品,服务器在向用户发送网页的同时,还发送了一段Cookie,记录着那项商品的信息。 当用户访问另一个页面,浏览器会把Cookie发送给服务器,于是服务器知道他之前选购了什么。 用户继续选购饮料,服务器就在原来那段Cookie里追加新的商品信息。 结帐时,服务器读取发送来的Cookie就行了。 Cookie另一个典型的应用是当登录一个网站时,网站往往会请求用户输入用户名和密码,并且用户可以勾选“下次自动登录”。 如果勾选了,那么下次访问同一网站时,用户会发现没输入用户名和密码就已经登录了。 这正是因为前一次登录时,服务器发送了包含登录凭据(用户名加密码的某种加密形式)的Cookie到用户的硬盘上。 第二次登录时,如果该Cookie尚未到期,浏览器会发送该Cookie,服务器验证凭据,于是不必输入用户名和密码就让用户登录了。

以上内容是维基百科对Cookie的解释,为什么有Cookie? 说白了: 因为浏览器与人需要一种交互,Cookie则实现了这种交互;服务器通过向用户发送Cookie给予了用户某种“权限”,这好比是一张门票,当浏览器携带着“门票”向服务器发起请求时,服务器通过验证“门票”信息就可以赋予用户某种“权限”。接下来我用注册与登陆的示例来简单地介绍下 Cookie的具体应用场景。

基本原理

8d9bc702a086320b21036b12867fb5cd.png

当浏览器向服务器发送请求的时候,服务器会将少量的数据以 set-cookie 消息头的方式发送给客户端, 浏览器一般会自动将 cookie 数据进行存储,当客户端再次访问服务器时,会将这些数据以 cookie 消息头的方式发送给服务器,服务端就可以根据 cookie 消息头来判别用户的身份或进行一些特别的处理并返回响应。

生存期

从 cookie 的工作原理上可以知道 cookie 信息主要是存储在客户端的状态, 而 cookie 在客户端的生存期则主要由属性 max-age 决定, max-age 属性以秒为单位表示 cookie 的存活时间为 max-age 秒; 当然 cookie 还有一个属性 expires 其作用和 max-age 是一样的这在后续会进行详细说明。

  • 默认情况下 cookie 只是暂时存在的,他们存储的值只在浏览器会话期间存在,当用户关闭浏览器窗口后这些值也会随之销毁(生成的 cookie 临时存储于浏览器内存中)
  • max-age 为正数: cookie 会在 max-age 秒之后被销毁(会将状态存储于 cookie 文件中并存储于本地硬盘中)
  • max-age 为负数时: cookie 只在浏览器会话期间存在,当用户关闭浏览器窗口后这些值也会随之销毁(生成的 cookie 临时存储于浏览器内存中)
  • max-age 为 0 时: cookie 将被立即销毁

Cookie细节

cookie编码

在tomcat 8 之前 cookie中不能直接存储中文数据。需要将中文数据转码---一般采用URL编码(%E3)

在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析。

举个例子 在服务器中的Servlet判断是否有一个名为lastTime的cookie

  1. 有:不是第一次访问
    1. 响应数据:欢迎回来,您上次访问时间为:2020年7月31日11:50:20
    2. 写回Cookie:lastTime=2020年7月31日11:50:20
  2. 没有:是第一次访问
    1. 响应数据:您好,欢迎您首次访问
    2. 写回Cookie:lastTime=2020年7月31日11:50:20
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应的消息体的数据格式以及编码
        response.setContentType("text/html;charset=utf-8");
        // 1.获取所有Cookie
        Cookie[] cookies = request.getCookies();
        boolean flag = false;//没有cookie为lastTime
        // 2.遍历cookie数组
        if(cookies != null && cookies.length > 0){
            for (Cookie cookie : cookies) {
                // 3.获取cookie的名称
                String name = cookie.getName();
                // 4.判断名称是否是:lastTime
                if("lastTime".equals(name)){
                    // 有该Cookie,不是第一次访问
                    flag = true;//有lastTime的cookie
                    // 设置Cookie的value
                    // 获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
                    Date date  = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                    String str_date = sdf.format(date);
                    System.out.println("编码前:"+str_date);
                    // URL编码
                    str_date = URLEncoder.encode(str_date,"utf-8");
                    System.out.println("编码后:"+str_date);
                    cookie.setValue(str_date);
                    // 设置cookie的存活时间
                    cookie.setMaxAge(60 * 60 * 24 * 30);// 一个月
                    response.addCookie(cookie);
                    // 响应数据
                    // 获取Cookie的value,时间
                    String value = cookie.getValue();
                    System.out.println("解码前:"+value);
                    // URL解码:
                    value = URLDecoder.decode(value,"utf-8");
                    System.out.println("解码后:"+value);
                    response.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");
                    break;
                }
            }
        }
        if(cookies == null || cookies.length == 0 || flag == false){
            // 没有,第一次访问
            // 设置Cookie的value
            // 获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
            Date date  = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String str_date = sdf.format(date);
            System.out.println("编码前:"+str_date);
            // URL编码
            str_date = URLEncoder.encode(str_date,"utf-8");
            System.out.println("编码后:"+str_date);
            Cookie cookie = new Cookie("lastTime",str_date);
            // 设置cookie的存活时间
            cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
            response.addCookie(cookie);
            response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");
        }

    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

cookie共享问题

浏览器的同源政策规定,两个网址,只要域名相同,端口相同,就可以共享Cookie 注意,这里不需要协议相同。

1.假设在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?

​ 默认情况下cookie不能共享

​ setPath(String path):设置cookie的获取范围。默认情况下,设置当前的虚拟目录

​ 如果要共享,则可以将path设置为"/"

2.不同的tomcat服务器间cookie共享问题?

​ setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享

​ setDomain(".http://baidu.com"),那么http://tieba.baidu.com和http://news.baidu.com中cookie可以共享

举个例子:

@WebServlet("/cookieDemo5")
public class CookieDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.创建Cookie对象
        Cookie c1 = new Cookie("msg","你好");
        //设置path,让当前服务器下部署的所有项目共享Cookie信息
        c1.setPath("/");

        //3.发送Cookie
        response.addCookie(c1);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

cookie注意点

Cookie在客户端,保存不敏感的数据,可能有安全问题,需要借助加密技术屏蔽敏感数据。并且大小不能超过4k,很多浏览器都限制一个站点最多保存20个cookie。HTTP是一个无状态协议,因此Cookie的最大的作用就是存储sessionId用来唯一标识用。

Cookie保存的是字符串。

一次可以发送多个cookie。

http协议下cookie是明文传递的,https协议下cookie是密文传递的。

子域名可以访问根域名的cookie,反之则不可以。

不同浏览器的 Cookie 不共享。

浏览器得到 Cookie 之后,每次请求都要带上 Cookie,无形中增加了流量。

Windows 的 Cookie 储存在C盘的一个文件夹中。

Cookie属性

name

cookie的名字,Cookie一旦创建,名称便不可更改。 可以是除了控制字符 (CTLs)、空格 (spaces) 或制表符 (tab)之外的任何 US-ASCII 字符。同时不能包含以下分隔字符: ( ) < > @ , ; : " / [ ] ? = { }。

value

cookie值 是可选的,如果存在的话,那么需要包含在双引号里面。支持除了控制字符(CTLs)、空格(whitespace)、双引号(double quotes)、逗号(comma)、分号(semicolon)以及反斜线(backslash)之外的任意 US-ASCII 字符。

domain 和 path 属性

domain 指定了该 cookie 所属的域名,默认情况下,domain 会被设置为创建该 cookie 时所在的域名; 而 path 则指定了该 cookie 所属的路径; domain 和 path 两者一起来限制了该 cookie 允许被哪些 URL 访问, 当我们请求某个资源(URL)时只有当该 URL 域名能够同时被 domain 和 path 属性匹配时, 浏览器才会将此 cookie 添加到该请求的 cookie 头部中。

domain 的匹配是根据请求 URL 中的域名从后向前进行匹配, path 的匹配则是根据 URL 中的路径按照路径的匹配规则判断 URL 中的路径是否包含 path, 例如:

domain 属性path 属性请求 URL请求是否包含 cookie描述http://auth.com/b.auth.com/a/d是http://-b.auth.com/ab.auth.com/a/b是http://-b.auth.com/bb.auth.com/a/b否path 属性不匹配,路径 /a/b 不包含 /http://bb.auth.com/cb.auth.com/a/b否path 属性不匹配,路径 /a/b 不包含 /http://ca.auth.com/b.auth.com/a/b否domain 不匹配

expires/max-age

首先需要知道清楚 expires 是 http/1.0 协议中的属性,在新的 http/1.1 协议之后 expires 已经由 max-age 选项代替,两者的作用都是限制 cookie 的有效时间。

expires 属性指定一个具体的到期时间,到了指定时间以后,浏览器就不再保留这个 cookie 。它的值是 UTC 格式,可以使用 Date.prototype.toUTCString() 进行格式转换。而 max-age 属性则是指定从现在开始 cookie 存在的秒数,比如 60 * 60 * 24 * 365 (即一年)。过了这个时间以后,浏览器就不再保留这个 cookie 。如果同时指定了 expires 和 max-age,那么 max-age 的值将优先生效。如果没有指定 expires 或 max-age 属性,那么这个 cookie 就是 Session Cookie, 即它只在本次对话存在,一旦用户关闭浏览器窗口, 浏览器将不会再保留这个 cookie 。如果同时指定了Expires和Max-Age,那么Max-Age的值将优先生效。

secure

该属性只是一个标记而没有值。包含 secure 选项的 cookie 只有在当请求是 HTTPS 或者其他安全协议时, 才能被发送至服务器。默认情况下, cookie 不会带 secure 选项(即为空)。所以默认情况下,不管是 HTTPS 协议还是 HTTP 协议的请求,cookie 都会被发送至服务端。但要注意一点,secure 选项只是限定了在安全情况下才可以传输给服务端,但并不代表你不能看到这个 cookie。同时需要注意的是, 如果想在客户端即网页中通过 js 去设置 secure 类型的 cookie,必须保证网页是 https 协议的。在http协议的网页中是无法设置 secure 类型 cookie 的。

httpOnly

httpOnly 背后的意思是告之浏览器该 cookie 绝不能通过 JavaScript 的 document.cookie 属性访问。设计该特征意在提供一个安全措施来帮助阻止通过 JavaScript 发起的跨站脚本攻击 (XSS) 窃取 cookie 的行为, 一旦设定这个标记,通过 documen.coookie 则不能再访问该 cookie。

sameSite

sameSite-cookies 是一种机制,用于定义 cookie 如何跨域发送,其目的主要是为了尝试阻止 CSRF (Cross-site request forgery 跨站请求伪造)以及 XSSI (Cross Site Script Inclusion (XSSI) 跨站脚本包含)攻击。

CSRF攻击简述: CSRF 攻击主要是盗用用户信息并发送恶意请求的一种攻击方式, 比如说某用户登录一个完全网站 A, A 站点返回一个能够标识用户身份的 cookie, 当用户无意中访问一个恶意网站 B, B 站点向 A 站点发起恶意请求, 这时请求中将会带上具有用户身份标识的 cookie。

XSSI攻击简述: XSSI 是 XSS 的一种形式, 假设网站 A 有一个脚本用于读取用户的私人账户信息, 攻击者可以在自己的恶意网站包含这个脚本, 当网站 A 的用户访问攻击者的网站时该网站将加载该脚本并带上用户身份标识 (cookie) 该脚本将读取用户的私人账户信息, 这时用户的信息可能就会发生泄露。

sameSite 属性可能值: 为 cookie 设置 sameSite 属性时需要给其定义一个值(如果没有设置值,默认是Strict),值可以是 Lax 或者 Strict

strict: 当 sameSite 属性值为 strict 时, 将禁止发送所有第三方链接的 cookies, 比如有 cookie ( domain = a.com, sameSite = strict ), 那么在其他网站请求 http://a.com 时都不会带上该 cookie

lax: 当 sameSite 属性值为 lax 时, 只会在使用危险 HTTP 方法发送跨域 cookie 的时候进行阻止,例如 POST 方式。比如有 cookie ( domain = a.com, sameSite = lax ), 那么在其他网站通过 POST 方式请求 http://a.com 时都不会带上该 cookie。

前端操作 cookie

创建 cookie

前端通过 document.cookie 设置 cookie, 设置多个 cookie 则需要编写多条 document.cookie = '...', 如果需要对 cookie 进行修改创建一条相同名称的 cookie 即可对 cookie 进行替换。

// 创建多条 cookie 并设置 path 和 domain 以及 max-age 属性
   document.cookie = 'name1=value1;path=/;domain=127.0.0.1;max-age=30';
   document.cookie = 'name2=value2;path=/;domain=127.0.0.1;max-age=30';
   document.cookie = 'name3=value3;path=/;domain=127.0.0.1;max-age=30';

   /**
     * 通用方法: 设置&emsp;cookie 方法
     * @param {String} name     cookie 名称
     * @param {String} value    cookie 值
     * @param {Number} maxAge   cookie 存活时间(maxAge秒, 默认存储 30 天)
   */
function setCookie({
     name,
     value,
     maxAge
}) {
     maxAge = maxAge || 30 * 24 * 60 * 60 * 1000;
     // escape: 对字符串进行编码
     document.cookie = `${name}=${escape (value)};max-age=${maxAge}`;
}

0b8d8ec7a34a9f267a0191404835f02f.png

获取 cookie

前端可直接通过 document.cookie 获取 cookie。

// 打印 cookie
console.log(document.cookie); // name1=value1; name2=value2; name3=value3

/**
 * 通用方法: 将 cookie 转为对象 {anme: value}
 * @return {Object} {name, value}
 */
function getCookieObj() {
  let cookieArr = document.cookie.split(";");
  let obj = {};
  cookieArr.forEach( v => {
    let arr = v.split("=");
    obj[arr[0]] =  unescape(arr[1]);
  });
  return obj
}

删除 cookie

前端并没有直接的 api 可以直接实现对 cookie 的删除, 可以通过将 cookie 的 max-age 属性设置 0 来实现对 cookie 的删除。

// 删除 cookie
document.cookie = 'name3=value3;max-age=0';

/**
 * 通用方法: 删除 cookie 方法
 * @param {String} name     cookie 名称
 */
function delCookie({ name }) {
  document.cookie = `${name}=;max-age=0`;
}

服务端操作 cookie

设置 cookie

@WebServlet("/cookieDemo3")
public class CookieDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.创建Cookie对象
        Cookie c1 = new Cookie("msg","hello");
        Cookie c2 = new Cookie("name","zhangsan");
        //2.发送Cookie
        response.addCookie(c1);
        response.addCookie(c2);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

删除cookie

@WebServlet("/cookieDemo4")
public class CookieDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.创建Cookie对象
        Cookie c1 = new Cookie("msg","setMaxAge");
        //2.设置cookie的存活时间
        //c1.setMaxAge(30);//将cookie持久化到硬盘,30秒后会自动删除cookie文件
        //c1.setMaxAge(-1);
        //c1.setMaxAge(300);
        c1.setMaxAge(0);//删除Cookie
        //3.发送Cookie
        response.addCookie(c1);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

Cookie 和 CSRF 的关系

1、CSRF是什么

CSRF,中文名叫跨站请求伪造,发生的场景就是,用户登陆了a网站,然后跳转到b网站,b网站直接发送一个a网站的请求,进行一些危险操作,就发生了CSRF攻击!

这时候,懂得这个CSRF了吗?我认为一部分同学依然不懂,因为我看过太多这样的描述了!

因为有这么一些疑惑,为什么在b网站可以仿造a网站的请求?Cookie不是跨域的吗?什么条件下,什么场景下,会发生这样的事情?

这时候,我们要注意上面我对cookie的定义,在发送一个http请求的时候,携带的cookie是这个http请求域的地址的cookie。也就是我在b网站,发送a网站的一个请求,携带的是a网站域名下的cookie!很多同学的误解,就是觉得cookie是跨域的,b网站发送任何一个请求,我只能携带b网站域名下的cookie。

当然,我们在b网站下,读取cookie的时候,只能读取b网站域名下的cookie,这是cookie的跨域限制。所以要记住,不要把http请求携带的cookie,和当前域名的访问权限的cookie混淆在一起。

还要理解一个点:CSRF攻击,仅仅是利用了http携带cookie的特性进行攻击的,但是攻击站点还是无法得到被攻击站点的cookie。这个和XSS不同,XSS是直接通过拿到Cookie等信息进行攻击的。

2、Cookie相关特性

在CSRF攻击中,就Cookie相关的特性:

1、http请求,会自动携带Cookie。

2、携带的cookie,还是http请求所在域名的cookie。

3、Cookie如何应对的 CSRF攻击?

明白了CSRF的本质,就能理解如何防御CSRF的攻击。

方案一:放弃Cookie、使用Token!

由于CSRF是通过Cookie伪造请求的方式,欺骗服务器,来达到自己的目的。那么我们采取的策略就是,不使用Cookie的方式来验证用户身份,我们使用Token!

Token的策略,一般就是登陆的时候,服务端在response中,返回一个token字段,然后以后所有的通信,前端就把这个token添加到http请求的头部。

这是当前,最常用的防御CSRF攻击的策略。

方案二:SameSite Cookies

前端在发展,Cookie也在进化,Cookie有一个新的属性——SateSite。能够解决CSRF攻击的问题。

它表示,只能当前域名的网站发出的http请求,携带这个Cookie。

当然,由于这是新的cookie属性,在兼容性上肯定会有问题。

方案三:服务端Referer验证

我们发送的http请求中,header中会带有Referer字段,这个字段代表的是当前域的域名,服务端可以通过这个字段来判断,是不是“真正”的用户请求。

也就是说,如果b网站伪造a网站的请求,Referer字段还是表明,这个请求是b网站的。也就能辨认这个请求的真伪了。

不过,目前这种方案,使用的人比较少。可能存在的问题就是,如果连Referer字段都能伪造,怎么办?

Cookie 和 XSS 的关系

1、XSS是什么

XSS是由于不安全的数据引起的,有可能是表单提交的数据,有可能是页面路径的参数问题。

CSRF是通过伪造http请求,来达到自己的攻击目的。但是XSS是通过盗取用户的敏感信息而达到攻击的目的。比如本地存储、用户密码、cookie等等。

比如这个不安全的数据,是一个script标签,那这个script就可以链接任意的js文件,浏览器本地就会执行这个js,那通过js我们能做的东西就太多了:

比如document.cookie,获取用户信息。

比如通过localStorage,获取本地存储的敏感信息(token)。

然后只要是这个页面展示的任何信息,我都可以获取。

2、Cookie 如何应对 XSS攻击

方案一:http-only

Cookie有一个http-only属性,表示只能被http请求携带。

假如你的网站遭受到XSS攻击,攻击者就无法通过document.cookie得到你的cookie信息。

方案二:正则校验

我们了解到,XSS是由于不安全的数据引起的,这些数据的来源,一个重要的渠道就是提交表单,注入到数据库。所以针对前端,我们需要把表单数据进行正则验证,通过验证之后,才能提交数据。

对于服务端,也应该对接受的数据,进行规则校验,不符合规则的数据不应该入库。从接口层面,保证数据安全。

方案三:数据转义

如果无法保证数据库的数据都是安全的,前端能做的事情就是,把所有需要展示到页面的数据,进行转义,比如遇到script标签,直接replace处理。或者遇到标签标识‘<’以及‘>’这类特殊字符,添加‘’进行处理。

Cookie 和 Token对比

Token 的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。Token 机制和 Cookie 和 Session 的使用机制比较类似。

1、cookie可以引起csrf攻击,token在保持用户会话的时候好一点。

2、由于http请求携带cookie,当cookie过大的时候,会增大http请求的带宽。

3、cookie的特性,导致了cookie面对CSRF攻击的时候,很不安全。

Cookie优化

从安全方面,尽量的使用token,进行会话保持。

从http请求的角度,尽可能让cookie的信息少一点,从而使得http请求的体积更小。

由于cookie的一个常用的作用,是保持用户会话的,所以仅仅在接口请求的时候,使用cookie。

加载其他资源,比如图片、js、css文件等等,可以托管到CDN上,这样就不会携带cookie,CDN的策略也使得资源加载更快。

Cookie的分类

会话级别Cookie:

所谓会话级别Cookie,就是在浏览器关闭之后Cookie就会失效。

持久级别Cookie:

保存在硬盘的Cookie,只要设置了过期时间就是硬盘级别Cookie。

好的,现在cookie保存在了客户端,当我们去请求一个URL时,浏览器会根据这个URL路径将符合条件的Cookie放在请求头中传给服务器。

使用 cookie 时需要考虑的问题

  • 因为存储在客户端,容易被客户端篡改,使用前需要验证合法性
  • 不要存储敏感数据,比如用户密码,账户余额
  • 使用 httpOnly 在一定程度上提高安全性
  • 尽量减少 cookie 的体积,能存储的数据量不能超过 4kb
  • 设置正确的 domain 和 path,减少数据传输
  • cookie 无法跨域
  • 一个浏览器针对一个网站最多存 20 个Cookie,浏览器一般只允许存放 300 个Cookie
  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

参考

参考:https://juejin.im/post/6844904102544031757

链接:https://juejin.im/post/6844903662909833229

链接https://baike.baidu.com/item/cookie/1119?fr=aladdin

链接:https://juejin.im/post/6844904034181070861

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值