.png)
Я планирую запускать потенциально опасные приложения(браузер и т. д.)на отдельном X-сервере, но поскольку у каждого сервера свой буфер обмена, невозможно скопировать ссылку/текст из одного окна в другое.
В большинстве статей предлагается делать это с помощью скриптов, использующих xclip и другие подобные утилиты.
Но какПРАВИЛЬНОсоздать общий буфер обмена, чтобы случайно не создать новую уязвимость?
решение1
ПРИМЕЧАНИЕ: Обновление ответа для отражения изменения стратегии - вместо запуска Xephyr на сервере/контейнере, я запускаю его на хосте/основной среде использования. Причина в том, что запуск Xephyr на сервере/контейнере - это как установка замка на внутреннюю дверь вместо входной - злоумышленники обошли бы внутреннюю дверь и получили бы доступ к буферу обмена напрямую через удаленный сокет X pipe.
Столкнувшись с той же проблемой уязвимости буфера обмена, я подошел к ее решению, запустив Xephyr на хосте (мое личное рабочее пространство) и перенаправив X с сервера-на-контейнере(ах) на локальный Xephyr.
Xephyr работает на дисплее ':2', в то время как мои окна личного рабочего пространства и браузер работают на дисплее по умолчанию ':0'. Эти два дисплея не используют общий буфер обмена — у каждого свой буфер обмена. Это единственный способ предотвратить слежку за моим личным буфером обмена на дисплее ':0'. Затем я настраиваю горячие клавиши (например, функциональные клавиши), одну для передачи содержимого буфера обмена с ':0' на ':2', а другую для ':2' на ':0', что обеспечивает полный контроль.
В скрипте оболочки код может выглядеть так:
xsel --display :0 --clipboard -o | xsel --display :2 --clipboard -i
хотя я использую JavaScript, как показано в нижней части этого поста.
Скрипт оболочки для запуска пересылки X может выглядеть примерно так:
Xephyr <args> :2
DISPLAY=:2 ssh -X -R 44713:localhost:4713 user@container <<EOF
DISPLAY=:10 PULSE_SERVER=tcp:localhost:44713 openbox --startup firefox
EOF
хотя я использую для этого программу JavaScript.
Вот код javascript для копирования между ':0' и ":2", который отображается горячими клавишами. Вы можете видеть, что он выводит временное окно сообщения для подтверждения того, что он сработал.
#!/usr/bin/env node
`strict`;
const child_process = require('child_process');
// TODO: write unviewable error messasges to system log
function notifySend(title, msg){
title = title.replace(/"/g, '\\"');
msg = msg.replace(/"/g, '\\"');
//msg = msg.replace(/'/g, '\\'')
try {
child_process.execSync(`notify-send "${title}" "${msg}"`);
} catch(e) {
console.log(`system call "notify-send" failed with ${e.message}`);
}
}
async function clipXfer(fromDispNum,toDispNum){
var clipValue;
let cmd1 = `xsel --display :${fromDispNum} --clipboard --output`;
let cmd2 = `xsel --display :${toDispNum} --clipboard --input`;
try {
clipValue = child_process.execSync(cmd1, { encoding: 'utf-8' });
} catch(e) {
throw Error(`Display ${fromDispNum} clipboard is empty`);
}
await new Promise((resolve, reject)=>{
// eslint-disable-next-line no-unused-vars
var proc = child_process.exec(cmd2, (error, stdout, stderr) => {
//if (stdout) console.log(stdout);
//if (stderr) console.log(stderr);
if (error) {
reject(Error(`${error.message}`));
}
resolve();
});
if (!proc.stdin.write(clipValue))
reject(Error('clipToCont(), pipe write failed'));
proc.stdin.end();
});
}
async function main()
{
let argOff=2;
if (process.argv.length-argOff<2)
throw Error('clip-xfer requires two arguments: fromDispNum, toDispNum');
let fromDispNum = process.argv[argOff];
let toDispNum = process.argv[argOff+1];
argOff+=2;
let f = (outcome)=>{
notifySend("clipXfer", `${fromDispNum} => ${toDispNum} ${outcome}`);
};
await clipXfer(fromDispNum,toDispNum)
.then(f('SUCCESS'))
.catch((e)=>{f(`FAILURE, ${e.message}`); throw e;});
}
//console.log(process.argv);
//console.log(process.env);
main()
.then(()=>{process.exitCode=0;})
.catch((e)=>{
console.log(e);
process.exitCode=1;
});