远程调用任意JS函数

远程调用任意JS函数

HTTP server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import time
from flask import Flask, request
import logging
import json
from websocket_server import WebsocketServer
import threading
import uuid


def recv_message(client, server, message):
print(message)
try:
d = json.loads(message)
_id = d.get('id')
data = d.get('data')
CACHE[_id] = data
except Exception as e:
print(e)
pass


CACHE = {}
app = Flask(__name__)
server = WebsocketServer(host='127.0.0.1', port=10086, loglevel=logging.INFO)
server.set_fn_message_received(recv_message)


class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)

def run(self):
server.run_forever()


@app.route("/")
def index():
data = request.args.get('data')
func_name = request.args.get('func_name')
if not data:
return "Hello, World!"
_id = uuid.uuid4().hex
d = {'data': data, "func_name": func_name, "id": _id}
msg = json.dumps(d)
print(msg)
try:
client = server.clients[-1]
except Exception as e:
client = None
if not client:
return 'Not connected!'
server.send_message(client, msg)
ts = time.time()
while True:
time.sleep(0.1)
data = CACHE.get(_id)
if data:
del (CACHE[_id])
return data
if time.time() - ts > 5:
break
return 'OK'


if __name__ == '__main__':
t = MyThread()
t.start()
app.run('0.0.0.0', 9999, debug=False)

Another html page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script src="crypto-js.min.js"></script>
<script>
var key = CryptoJS.enc.Utf8.parse('1111111111111111');
var iv = CryptoJS.enc.Utf8.parse('0000000000000000');

function test_encrypt(s) {
var input = CryptoJS.enc.Utf8.parse(s);
encrypted = CryptoJS.AES.encrypt(input, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return encrypted.ciphertext.toString(CryptoJS.enc.Base64)
}

function test_decrypt(s) {
decrypted = CryptoJS.AES.decrypt(s, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return decrypted.toString(CryptoJS.enc.Utf8)
}

</script>

Run js in console:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const ws = new WebSocket("ws://localhost:10086/");
ws.onopen = function () {
console.log("WebSocket Client Connected");
};

ws.onmessage = function (e) {
console.log(e)
var obj = JSON.parse(e.data)
var func_name = obj.func_name
var data = obj.data
var id = obj.id
if (func_name === "test_encrypt") {
var result = test_encrypt(data)
var msg = JSON.stringify({ 'id': id, 'data': result })
ws.send(msg)
}
if (func_name === "test_decrypt") {
var result = test_decrypt(data)
var msg = JSON.stringify({ 'id': id, 'data': result })
ws.send(msg)
}
};

远程调用:

1
2
3
http://localhost:9999/?data=2222&func_name=test_encrypt

http://localhost:9999/?data=vctKhKpbboUox82pkoqx%2Bg%3D%3D&func_name=test_decrypt

2023-7-1 更新

Python的websocket在实际使用中存在比较慢的情况。于是尝试进行优化。

使用nodejs的ws库创建一个websocket server,将所有收到的消息广播出来,python端则不再需要http server,直接发送、接收websocket消息即可。

1
2
# ws库地址
https://github.com/websockets/ws

配置环境:

1
2
3
4
npm install ws

npm install babel-cli -g
npm install babel-preset-env -D

ws_server.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import WebSocket, { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 3000 });

wss.on('connection', function connection(ws) {
ws.on('error', console.error);

ws.on('message', function message(data, isBinary) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data, { binary: isBinary });
}
});
});
});

启动websocket服务:

1
babel-node --presets env ws_server.js

Python端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def test(data):
signstr = ''
d = {"data": data, "func_name": "test_encrypt", "id": _id}
ws_url = "ws://localhost:3000/"
ws = websocket.WebSocket()
ws.connect(ws_url)
ws.send(json.dumps(data))
for _ in range(100):
signstr = ws.recv()
if _id in signstr:
dd = json.loads(signstr)
signstr = dd.get('data')
break
time.sleep(0.1)
ws.close()
return signstr