9.3. X ForwardingNow that you've seen general TCP port forwarding, we move to a new topic: forwarding of X protocol connections. X is a popular window system for Unix workstations, and one of its best features is its transparency. Using X, you can run remote X applications that open their windows on your local display (and vice versa, running local applications on remote displays). Unfortunately, the inter-machine communication is insecure and wide open to snoopers. But there's good news: SSH X forwarding makes the communication secure by tunneling the X protocol. X forwarding also addresses some firewall-related difficulties. Suppose you're a system administrator with a set of exposed production machines on the other side of a firewall from you. You log into one of these machines using SSH, and want to run an graphical performance-monitoring tool, such as Solaris's perfmon, that uses the X Window System. You can't, though, because to do that, the external machine needs to make a TCP connection back to the internal machine you started on, and the firewall blocks it (as it should, since X is quite insecure). X forwarding solves this problem, permitting X protocol connections to pass through the firewall, securely tunneled via SSH. Our discussion begins with a brief overview of X and then explains the details of X forwarding. In addition to explaining how to use X forwarding, we also expose the internals of X authentication and how it interacts with SSH, as well as other technical topics.
9.3.1. The X Window SystemThe X Window System, or X, is the most widely used graphical display system for Unix machines. Like SSH, X has clients and servers. X clients are windowing application programs, such as terminal emulators, paint programs, graphical clocks, and so forth. An X server is the underlying display engine that processes requests from X clients, communicating via a network protocol called the X protocol. A machine typically runs a single X server but possibly many X clients. Most important to our discussion, X supports sophisticated window management over a network. X clients can open windows not only on their local machine but also on other computers on the network, whether they are down the hall or across the globe. To accomplish this, an X client makes a network connection to a remote X server and carries on a conversation, using the X protocol to draw on the remote screen, receive remote keyboard events, learn the remote mouse location, and so on. This obviously requires some type of security, which we discuss soon. A central concept of X is the display, an abstraction for the screen managed by an X server. When an X client is invoked, it needs to know which display to use. Displays are named by strings of the form HOST:n.v, where:
or the environment variable:$ xterm -d anacreon:0 &
X is a large, deep software product whose documentation fills a dozen O'Reilly books. We've barely scratched the surface with our explanation, but you've now seen enough to understand X forwarding.$ setenv DISPLAY anacreon:0 $ xterm &
9.3.2. How X Forwarding WorksAlthough X clients can communicate with remote X servers, this communication isn't secure. All interactions between the X client and server, such as keystrokes and displayed text, can be easily monitored by network snooping because the connection isn't encrypted. In addition, most X environments use primitive authentication methods for connecting to a remote display. A knowledgeable attacker can get a connection to your display, monitor your keystrokes, and control other programs you're running. Once again, SSH comes to the rescue. An X protocol connection can be routed through an SSH connection to provide security and stronger authentication. This feature is called X forwarding. X forwarding works in the following way. (As illustration, please refer to Figure 9-10.) An SSH client requests X forwarding when it connects to an SSH server (assuming X forwarding is enabled in the client). If the server allows X forwarding for this connection, your login proceeds normally, but the server takes some special steps behind the scenes. In addition to handling your terminal session, it sets itself up as a proxy X server running on the remote machine and sets the DISPLAY environment variable in your remote shell to point to the proxy X display:
syrinx$ ssh sys1 Last login: Sat Nov 13 01:10:37 1999 from blackberry Sun Microsystems Inc. SunOS 5.6 Generic August 1997 You have new mail. sys1$ echo $DISPLAY sys1:10.0 sys1$ xeyes The "xeyes" X client appears on the screen
Figure 9-10. X forwardingThe DISPLAY value appears to refer to X display #10 on sys1, but there's no such display. (In fact, there might be no true displays on sys1 at all.) Instead, the DISPLAY value points to the X proxy established by the SSH server, i.e., the SSH server is masquerading as an X server. If you now run an X client program, it connects to the proxy. The proxy behaves just like a "real" X server, and in turn instructs the SSH client to behave as a proxy X client, connecting to the X server on your local machine. The SSH client and server then cooperate to pass X protocol information back and forth over the SSH pipe between the two X sessions, and the X client program appears on your screen just as if it had connected directly to your display. That's the general idea of X forwarding. X forwarding can even solve the firewall problem mentioned earlier, as long as the firewall permits SSH connections to pass through. If a firewall sits between your local and remote machines, and you run an X client on the remote machine, X forwarding tunnels the X connection through the firewall's SSH port to the local machine. Therefore, the X client's windows can open on your local display. If X forwarding isn't present, the firewall blocks the connection. Some aspects of X forwarding probably sound familiar from our earlier explanation of port forwarding. In fact, X forwarding is just a special case of port forwarding for which SSH has special support.
9.3.3. Enabling X ForwardingX forwarding is on by default in SSH1 and SSH2, but off in OpenSSH. If you need to enable or disable X forwarding for your clients, here's how to do it. Unlike general port forwarding, which requires you to fiddle with TCP port numbers, X forwarding has only an on/off switch. In your SSH client configuration file, use the keyword ForwardX11 with a value yes (the default, to enable) or no (to disable):
On the command line, you may also use -x to disable X forwarding:# SSH1, SSH2, OpenSSH ForwardX11 yes
SSH2 and OpenSSH enables X forwarding with the following options:# SSH1, SSH2, OpenSSH $ ssh -x server.example.com
# SSH2 only $ ssh2 +x server.example.com # OpenSSH only $ ssh -X server.example.com
9.3.4. Configuring X ForwardingThe behavior of X forwarding can be modified through compile-time configuration, serverwide configuration, and per-account configuration.
220.127.116.11. Compile-time configurationSSH1 and SSH2 can be compiled with or without X support. The compile-time flags --with-x and -- without-x make this determination:
In addition, if you compile with X support, you may set the default behavior for X forwarding. In SSH1, you can enable or disable forwarding by default in the client and the server separately, using the compile-time flags -- enable-client-x11-forwarding (or -- disable-client-x11-forwarding) and -- enable-server-x11-forwarding (or -- disable-server-x11-forwarding):# SSH1, SSH2 $ configure ... --without-x ...
In SSH2, you can enable or disable all X forwarding by default with -- enable-X11-forwarding or -- disable-X11-forwarding:# SSH1 only $ configure ... --disable-server-x11-forwarding ...
Remember, enable/disable flags simply set the default behavior. You can override these defaults with serverwide and per-account configuration.# SSH2 only $ configure ... --enable-X11-forwarding ...
18.104.22.168. Serverwide configurationThe serverwide configuration keywords X11Forwarding (SSH1, SSH2, OpenSSH) and its synonyms ForwardX11 (SSH2) and AllowX11Forwarding (SSH2) enable or disable X forwarding in the SSH server. By default, it is enabled:
The X11DisplayOffset keyword lets you reserve some X11 display numbers so sshd can't use them. This keyword specifies the lowest display number SSH may use, preventing sshd from clashing with real X servers on the lower-numbered displays. For example, if you normally run actual X servers on displays and 1, set:# SSH1, SSH2, OpenSSH X11Forwarding no # SSH2 only: either will work ForwardX11 no AllowX11Forwarding no
The XAuthLocation keyword specifies the path to the xauth program, which manipulates authorization records for X. We describe this keyword later, after we discuss xauth. [Section 22.214.171.124, "Location of the xauth program"]# SSH1, OpenSSH X11DisplayOffset 2
# SSH1, OpenSSH XAuthLocation /usr/local/bin/xauth
126.96.36.199. Per-account configurationIn your SSH1 or OpenSSH authorized_keys file, you may disallow X forwarding for incoming SSH connections that use a particular key for authentication. This is done with the option no-X11-forwarding: [Section 8.2.8, "Disabling Forwarding "]
# SSH1, OpenSSH no-X11-forwarding ...rest of key...
9.3.5. X AuthenticationWe've mentioned in passing that X performs its own authentication when X clients connect to X servers. Now we're going to dive into technical detail on the inner workings of X authentication, why it's insecure, and how SSH X forwarding builds on it to create a secure solution. In most cases, X forwarding simply works, and you don't have to think about it. The following material is to aid your understanding and satisfy any intense cravings for tech talk (both yours and ours).
188.8.131.52. How X authentication worksWhen an X client requests a connection to an X server, the server authenticates the client. That is, the X server determines the client's identity to decide whether to allow a connection to the server's display. The current release of the X Window system (X11R6) provides two categories of authentication: host-based and key-based:
184.108.40.206. xauth and the SSH rc filesSSH has startup files that can be set to execute on the server side when a client logs in. These are the systemwide /etc/sshrc and the per-account ~/.ssh/rc. These can be shell scripts or any kind of executable program. An important thing to note is that sshd runs xauth only to add the proxy display key if it doesn't run an rc program. If it does run an rc program, it feeds the key type and data to the program on a single line to its standard input, and it is up to the rc program to store the display key. This feature provides a way to customize handling the display key, in case just running xauth isn't the right thing to do in your situation.
220.127.116.11. Problems with X authenticationIf you've used X, the authentication was probably transparent and seemed to work fine. Behind the scenes, however, the mechanism is insecure. Here are the major problems:
18.104.22.168. SSH and authentication spoofingThrough X forwarding, SSH provides transparent, secure authentication and key transfer for X sessions. This is done by a technique called authentication spoofing, as depicted in Figure 9-11. Authentication spoofing involves a fake display key, which we call the proxy key, that authenticates access to the SSH X proxy server on the remote side. When relaying X traffic containing a key, SSH cleverly substitutes the real display key. Here's how it works.
Figure 9-11. Authentication of forwarded X connectionsThe players begin in the following positions. You are logged into a local machine with a local display. The local machine runs an X server and SSH clients. On the other side of the network connection, an SSH server is running on a remote machine, where you invoke X clients. The goal is for the remote X clients to appear on your local display by way of SSH. First, you run a local SSH client, asking it to set up X forwarding. The SSH client requests X forwarding from the remote SSH server, and it also reads your local display key from your .Xauthority file. Next, the SSH client generates a proxy key. This is a string of random data of the same length as your local display key. The SSH client then sends the proxy key and its key type (e.g., MIT-MAGIC-COOKIE-1) to the remote machine, and the SSH server runs the xauth program on your behalf to associate the proxy key with your local display. The stage is now set for X forwarding. When you start a remote X client, your local SSH client connects to your local X display. It then watches for the first X protocol message sent over the forwarded connection and treats it specially. Specifically, the SSH client parses the message, finds the X authentication key inside it, and compares it to the proxy key. If the keys don't match, the SSH client rejects and closes the connection. Otherwise, if the keys match, the SSH client substitutes the real display key in place of the proxy key and relays the modified message to your local X server. The X server, blissfully unaware that a key switch has taken place, reads the display key and proceeds normally with X authentication. The forwarded X connection is now established. X forwarding with authentication spoofing solves all but one of the X authentication problems we raised earlier:
22.214.171.124. Improving authentication spoofingThe remaining problem with X forwarding is the possibility of unsupported X authentication mechanisms. The local side can use a more sophisticated authentication method a remote host might not support. In theory, SSH X forwarding can solve this problem by always installing a proxy key of type MIT-MAGIC-COOKIE-1, no matter what local authentication method is actually in use. After the SSH client has checked the X client's key against the proxy key for a match, its client could then generate and substitute whatever local authenticator is required using the true authentication type and key. Unfortunately, SSH implementations don't go this far. The server compares keys literally as bit strings, and the SSH client substitutes keys verbatim, regardless of the key types. As a result, if you use a stronger X authentication method such as XDM-AUTHORIZATION-1, sshd blindly compares an encrypted authenticator with the proxy key, rightly determine that they don't match, and invalidly rejects the connection. The failure is silent and mysterious; we wish the software would detect the presence of an unsupported mode and issue a warning when setting up the connection. If SSH knew the details of all X authentication modes, it could check the proxy authenticators on one side and generate correct ones for the X server on the other. However, this is a significant development effort, though perhaps one could link SSH against the X11 libraries to obtain the necessary algorithms. SSH would also have to deal with differing key data lengths, constructing a new X message to hold the proxy key instead of copying it to an existing message. It would also be useful if X forwarding could be used without authentication spoofing. Then you could arrange your own security for the connection by, say, using xhost to allow any connection from your local machine (and hence the SSH X proxy), while still applying key-based authentication to X connections originating from elsewhere. You can accomplish this with general port forwarding, as discussed in the next section, but direct support is more convenient.
126.96.36.199. Nonstandard X clientsX clients generally do X xauth-style authentication by virtue of having been linked against Xlib, the common X programming library. Occasionally, though, you run across particular X client programs that don't use Xlib and simply ignore authentication issues. Since you can't turn off SSH X authentication spoofing, you can't use such programs across SSH X forwarding; you get this message:
You can, however, use a general port forwarding instead. For example:X11 connection requests different authenticationprotocol: 'MIT-MAGIC-COOKIE-1' vs. ''
Note that this bypasses the discipline imposed by X forwarding, of requiring xauth authentication on forwarded X connections. If your real X server is using xhost for access control, this port forwarding allows anyone on host foo to connect to your X server. Use this sort of thing with caution if you need to.foo% ssh -R6010:localhost:6000 bar bar% setenv DISPLAY bar:10
9.3.6. Further IssuesAs we've said, X forwarding usually works fine without any special effort on your part. In some special situations, however, you might need to take some extra steps.
188.8.131.52. X server configurationIn order for X forwarding to work, your X server must accept the proxy X connections from your SSH client. This is sometimes not set up to begin with, because normal use doesn't require it. For example, if you're using an X server on a PC to access a remote Unix machine via XDM, you might never run local X clients at all, and they may not be allowed by default. You can run xhost +localhost to allow all connections from the your PC, while still applying key-based authentication to connections from other sources. This allows SSH-forwarded (and authenticated) connections to be accepted.
184.108.40.206. Setting your DISPLAY environment variableSSH sets the DISPLAY variable automatically only if X forwarding is in effect. If you don't use X forwarding but want to use X on a remote machine you logged into via SSH, remember that you have to set the DISPLAY variable yourself. You should only do this when the both machines are on the same, trusted network, as the X protocol by itself is quite insecure. Be careful not to set DISPLAY unintentionally! It is common for people to set the DISPLAY variable in a login command file or by other means. If you're not careful, this can make your X connections insecure without your noticing. If you use SSH to tunnel through a firewall that blocks normal X connections, then of course you'll notice because your X clients won't work. But if normal X connections are possible but undesirable, and X forwarding isn't in effect, your X programs will work but will (silently) not be secured. This is a good reason to block X traffic at the firewall if it presents a security risk or to configure your X server to accept connections only from the local host (the source of the SSH-forwarded X connections). If that's not feasible, you may want to put something like this in your login script:
#!/bin/csh if ($?DISPLAY) then set display_host = `expr "$DISPLAY" : '\(.*\):'` set display_number = `expr "$DISPLAY" : '.*:\([^.]*\)'` set my_host = `hostname` set result = `expr '(' "$display_host" = "$my_host" ')' '&' '(' \ "$display_number" '>' "0" ')'` if ($result == 0) then echo "WARNING: X display $DISPLAY does not appear to be protected by SSH!" echo "unsetting DISPLAY variable just to be safe" unsetenv DISPLAY endif endif
220.127.116.11. Shared accountsIf you share a single account among multiple people, you may have some trouble with X forwarding. For example, it is common for a group of sysadmins to share use of the root account. For each person to retain their own environment when using the root account, they may set their USER, LOGNAME, and HOME environment variables explicitly to reflect their personal accounts rather than the root account. If you use SSH to log into the root account with X forwarding turned on, though, it adds the proxy xauth key to root's .Xauthority file before the shell reads your login script and resets these environment variables. The result is that once you're logged in and try to use X, it fails: the X client looks in your .Xauthority file (because of the setting of your HOME variable), but the key isn't there. You can deal with this problem by setting the XAUTHORITY variable to point to root's .Xauthority file, or by using code like the following in your login script to copy the needed key into your personal one:
if (($uid == 0) && ($?SSH_CLIENT) && ($?DISPLAY)) then # If I do ssh -l root with X forwarding, the X proxy server's xauth key # gets added to root's xauth db, not mine. See if there's an entry for my # display in root's xauth db... set key = `bash -c "xauth -i -f /.Xauthority list $DISPLAY 2> /dev/null"` # ... and if so, copy it into mine. if ($? == 0) then xauth -bi add $key chown res ~res/.Xauthority >& /dev/null endif endif
18.104.22.168. Location of the xauth programRemember that sshd runs the xauth program on your behalf, to add the proxy key to your .Xauthority file on the remote side. The location of the xauth program is discovered when you configure the SSH package and compiled into the sshd executable. If xauth is subsequently moved, X forwarding won't work (ssh -v reveals this explicitly). For SSH1 and OpenSSH, the system administrator on the server side can use the serverwide configuration keyword XAuthLocation to set the path to the xauth program without having to recompile sshd1:
XAuthLocation can also appear in the client configuration file (OpenSSH only); the client uses xauth to get the local X display key.# SSH1, Open SSH XAuthLocation /usr/local/bin/xauth
22.214.171.124. X forwarding and the GatewayPorts featureThe GatewayPorts (-g) feature discussed earlier applies only to general port forwarding, not to X forwarding. The X proxies in SSH1, SSH2, and OpenSSH always listen on all network interfaces and accept connections from anywhere, though those connections are then subject to X authentication as described earlier. To restrict X client source addresses, use TCP-wrappers, which we discuss in the next section.
Copyright © 2002 O'Reilly & Associates. All rights reserved.